Skip to main content

vizia_core/modifiers/
style.rs

1use vizia_style::{ColorStop, CornerRadius, Rect};
2
3use super::internal;
4use crate::prelude::*;
5
6/// Modifiers for changing the style properties of a view.
7pub trait StyleModifiers: internal::Modifiable {
8    // Selectors
9
10    /// Sets the ID name of the view.
11    ///
12    /// A view can have only one ID name and it must be unique.
13    /// The ID name can be referenced by a CSS selector.
14    /// # Example
15    /// ```
16    /// # use vizia_core::prelude::*;
17    /// # let cx = &mut Context::default();
18    /// Element::new(cx).id("foo");
19    /// ```
20    /// css
21    /// ```css
22    /// #foo {
23    ///     background-color: red;
24    /// }
25    ///```
26    fn id(mut self, id: impl Into<String>) -> Self {
27        // TODO - What should happen if the id already exists?
28        let id = id.into();
29        let entity = self.entity();
30        self.context().style.ids.insert(entity, id.clone());
31        self.context().needs_restyle(entity);
32
33        self.context().entity_identifiers.insert(id, entity);
34
35        self
36    }
37
38    /// Adds a class name to the view.
39    ///
40    /// A view can have multiple classes.
41    /// The class name can be referenced by a CSS selector.
42    /// # Example
43    /// ```
44    /// # use vizia_core::prelude::*;
45    /// # let cx = &mut Context::default();
46    /// Element::new(cx).class("foo");
47    /// ```
48    /// css
49    /// ```css
50    /// .foo {
51    ///     background-color: red;
52    /// }
53    ///```
54    fn class(mut self, name: &str) -> Self {
55        let entity = self.entity();
56        if let Some(class_list) = self.context().style.classes.get_mut(entity) {
57            class_list.insert(name.to_string());
58        }
59
60        self.context().needs_restyle(entity);
61
62        self
63    }
64
65    /// Sets whether a view should have the given class name.
66    fn toggle_class(mut self, name: &str, applied: impl Res<bool>) -> Self {
67        let name = name.to_owned();
68        let entity = self.entity();
69        let current = self.current();
70        self.context().with_current(current, |cx| {
71            applied.set_or_bind(cx, move |cx, applied| {
72                let applied = applied.get_value(cx);
73                if let Some(class_list) = cx.style.classes.get_mut(entity) {
74                    if applied {
75                        class_list.insert(name.clone());
76                    } else {
77                        class_list.remove(&name);
78                    }
79                }
80
81                cx.needs_restyle(entity);
82            });
83        });
84
85        self
86    }
87
88    // PseudoClassFlags
89    // TODO: Should these have their own modifiers trait?
90
91    /// Sets the checked state of the view.
92    fn checked<U: Into<bool>>(mut self, state: impl Res<U>) -> Self {
93        let entity = self.entity();
94        let current = self.current();
95        // Setting a checked state should make it checkable
96        if let Some(abilities) = self.context().style.abilities.get_mut(entity) {
97            abilities.set(Abilities::CHECKABLE, true);
98        }
99
100        self.context().with_current(current, move |cx| {
101            state.set_or_bind(cx, move |cx, val| {
102                let val = val.get_value(cx).into();
103                if let Some(pseudo_classes) = cx.style.pseudo_classes.get_mut(entity) {
104                    pseudo_classes.set(PseudoClassFlags::CHECKED, val);
105                }
106                cx.needs_restyle(entity);
107                cx.style.needs_access_update(entity);
108            });
109        });
110
111        self
112    }
113
114    /// Sets the focused state of the view.
115    ///
116    /// Since only one view can have keyboard focus at a time, subsequent calls to this
117    /// function on other views will cause those views to gain focus and this view to lose it.
118    fn focused<U: Into<bool>>(mut self, state: impl Res<U>) -> Self {
119        let entity = self.entity();
120        let current = self.current();
121
122        self.context().with_current(current, |cx| {
123            state.set_or_bind(cx, move |cx, val| {
124                let val = val.get_value(cx).into();
125
126                if val {
127                    cx.focus();
128                    // cx.focus_with_visibility(true);
129                }
130
131                cx.needs_restyle(entity);
132            });
133        });
134
135        self
136    }
137
138    /// Sets the focused state of the view as well as the focus visibility.
139    fn focused_with_visibility<U: Into<bool>>(
140        mut self,
141        focus: impl Res<U> + Copy + 'static,
142        visibility: impl Res<U> + Copy + 'static,
143    ) -> Self {
144        let entity = self.entity();
145        let current = self.current();
146
147        self.context().with_current(current, move |cx| {
148            focus.set_or_bind(cx, move |cx, f| {
149                visibility.set_or_bind(cx, move |cx, v| {
150                    let focus = f.get_value(cx).into();
151                    let visibility = v.get_value(cx).into();
152                    if focus {
153                        //cx.focus();
154                        cx.focus_with_visibility(visibility);
155                        cx.needs_restyle(entity);
156                    }
157                });
158            });
159        });
160
161        self
162    }
163
164    /// Sets whether the view should be in a read-only state.
165    fn read_only<U: Into<bool>>(mut self, state: impl Res<U>) -> Self {
166        let entity = self.entity();
167        let current = self.current();
168        self.context().with_current(current, |cx| {
169            state.set_or_bind(cx, move |cx, val| {
170                let val = val.get_value(cx).into();
171                if let Some(pseudo_classes) = cx.style.pseudo_classes.get_mut(entity) {
172                    pseudo_classes.set(PseudoClassFlags::READ_ONLY, val);
173                }
174
175                cx.needs_restyle(entity);
176            });
177        });
178
179        self
180    }
181
182    /// Sets whether the view should be in a read-write state.
183    fn read_write<U: Into<bool>>(mut self, state: impl Res<U>) -> Self {
184        let entity = self.entity();
185        let current = self.current();
186        self.context().with_current(current, |cx| {
187            state.set_or_bind(cx, move |cx, val| {
188                let val = val.get_value(cx).into();
189                if let Some(pseudo_classes) = cx.style.pseudo_classes.get_mut(entity) {
190                    pseudo_classes.set(PseudoClassFlags::READ_WRITE, val);
191                }
192
193                cx.needs_restyle(entity);
194            });
195        });
196
197        self
198    }
199
200    /// Sets whether any descendant of the view has keyboard focus.
201    fn focus_within<U: Into<bool>>(mut self, state: impl Res<U>) -> Self {
202        let entity = self.entity();
203        let current = self.current();
204        self.context().with_current(current, |cx| {
205            state.set_or_bind(cx, move |cx, val| {
206                let val = val.get_value(cx).into();
207                if let Some(pseudo_classes) = cx.style.pseudo_classes.get_mut(entity) {
208                    pseudo_classes.set(PseudoClassFlags::FOCUS_WITHIN, val);
209                }
210
211                cx.needs_restyle(entity);
212            });
213        });
214
215        self
216    }
217
218    /// Sets whether the view is showing a placeholder.
219    fn placeholder_shown<U: Into<bool>>(mut self, state: impl Res<U>) -> Self {
220        let entity = self.entity();
221        let current = self.current();
222        self.context().with_current(current, |cx| {
223            state.set_or_bind(cx, move |cx, val| {
224                let val = val.get_value(cx).into();
225                if let Some(pseudo_classes) = cx.style.pseudo_classes.get_mut(entity) {
226                    pseudo_classes.set(PseudoClassFlags::PLACEHOLDER_SHOWN, val);
227                }
228
229                cx.needs_restyle(entity);
230            });
231        });
232
233        self
234    }
235
236    modifier!(
237        /// Sets the view to be disabled.
238        ///
239        /// This property is inherited by the descendants of the view.
240        disabled,
241        bool,
242        SystemFlags::RESTYLE | SystemFlags::REACCESS
243    );
244
245    modifier!(
246        /// Sets whether the view should be positioned and rendered.
247        ///
248        /// A display value of `Display::None` causes the view to be ignored by both layout and rendering.
249        display,
250        Display,
251        SystemFlags::RELAYOUT | SystemFlags::REDRAW
252    );
253
254    modifier!(
255        /// Sets whether the view should be rendered.
256        ///
257        /// The layout system will still compute the size and position of an invisible (hidden) view.
258        visibility,
259        Visibility,
260        SystemFlags::REDRAW
261    );
262
263    modifier!(
264        /// Sets the opacity of the view.
265        ///
266        /// Exects a value between 0.0 (transparent) and 1.0 (opaque).
267        opacity,
268        Opacity,
269        SystemFlags::REDRAW
270    );
271
272    /// Sets the z-index of the view.
273    ///
274    /// Views with a higher z-index will be rendered on top of those with a lower z-order.
275    /// Views with the same z-index are rendered in tree order.
276    fn z_index<U: Into<i32>>(mut self, value: impl Res<U>) -> Self {
277        let entity = self.entity();
278        // value.set_or_bind(self.context(), |cx, v| {
279        let cx = self.context();
280        let value = value.get_value(cx).into();
281        cx.style.z_index.insert(entity, value);
282        cx.needs_redraw(entity);
283        // });
284
285        self
286    }
287
288    /// Sets the clip path for the the view.
289    fn clip_path<U: Into<ClipPath>>(mut self, value: impl Res<U>) -> Self {
290        let entity = self.entity();
291        let current = self.current();
292        self.context().with_current(current, |cx| {
293            value.set_or_bind(cx, move |cx, v| {
294                let value = v.get_value(cx).into();
295                cx.style.clip_path.insert(entity, value);
296                cx.needs_reclip(entity);
297                cx.needs_redraw(entity);
298            });
299        });
300
301        self
302    }
303
304    /// Sets the overflow behavior of the view in the horizontal and vertical directions simultaneously.
305    fn overflow<U: Into<Overflow>>(mut self, value: impl Res<U>) -> Self {
306        let entity = self.entity();
307        let current = self.current();
308        self.context().with_current(current, |cx| {
309            value.set_or_bind(cx, move |cx, v| {
310                let value = v.get_value(cx).into();
311                cx.style.overflowx.insert(entity, value);
312                cx.style.overflowy.insert(entity, value);
313                cx.needs_reclip(entity);
314                cx.needs_redraw(entity);
315            });
316        });
317
318        self
319    }
320
321    modifier!(
322        /// Sets the overflow behavior of the view in the horizontal direction.
323        ///
324        /// The overflow behavior determines whether child views can render outside the bounds of their parent.
325        overflowx,
326        Overflow,
327        SystemFlags::RECLIP | SystemFlags::REDRAW
328    );
329
330    modifier!(
331        /// Sets the overflow behavior of the view in the vertical direction.
332        ///
333        /// The overflow behavior determines whether child views can render outside the bounds of their parent.
334        overflowy,
335        Overflow,
336        SystemFlags::RECLIP | SystemFlags::REDRAW
337    );
338
339    /// Sets the filter for the view.
340    fn filter<U: Into<Filter>>(mut self, value: impl Res<U>) -> Self {
341        let entity = self.entity();
342        let current = self.current();
343        self.context().with_current(current, |cx| {
344            value.set_or_bind(cx, move |cx, v| {
345                let value = v.get_value(cx).into();
346                cx.style.filter.insert(entity, value);
347
348                cx.needs_redraw(entity);
349            });
350        });
351
352        self
353    }
354
355    /// Sets the backdrop filter for the view.
356    fn backdrop_filter<U: Into<Filter>>(mut self, value: impl Res<U>) -> Self {
357        let entity = self.entity();
358        let current = self.current();
359        self.context().with_current(current, |cx| {
360            value.set_or_bind(cx, move |cx, v| {
361                let value = v.get_value(cx).into();
362                cx.style.backdrop_filter.insert(entity, value);
363
364                cx.needs_redraw(entity);
365            });
366        });
367
368        self
369    }
370
371    /// Add a shadow to the view.
372    fn shadow<U: Into<Shadow>>(mut self, value: impl Res<U>) -> Self {
373        let entity = self.entity();
374        let current = self.current();
375        self.context().with_current(current, |cx| {
376            value.set_or_bind(cx, move |cx, v| {
377                let value = v.get_value(cx).into();
378                if let Some(shadows) = cx.style.shadow.get_inline_mut(entity) {
379                    shadows.push(value);
380                } else {
381                    cx.style.shadow.insert(entity, vec![value]);
382                }
383
384                cx.needs_redraw(entity);
385            });
386        });
387
388        self
389    }
390
391    /// Set the shadows of the view.
392    fn shadows<U: Into<Vec<Shadow>>>(mut self, value: impl Res<U>) -> Self {
393        let entity = self.entity();
394        let current = self.current();
395        self.context().with_current(current, |cx| {
396            value.set_or_bind(cx, move |cx, v| {
397                let value = v.get_value(cx).into();
398
399                cx.style.shadow.insert(entity, value);
400
401                cx.needs_redraw(entity);
402            });
403        });
404
405        self
406    }
407
408    /// Set the background gradient of the view.
409    fn background_gradient<U: Into<Gradient>>(mut self, value: impl Res<U>) -> Self {
410        let entity = self.entity();
411        let current = self.current();
412        self.context().with_current(current, |cx| {
413            value.set_or_bind(cx, move |cx, v| {
414                let value = v.get_value(cx).into();
415                if let Some(background_images) = cx.style.background_image.get_inline_mut(entity) {
416                    background_images.push(ImageOrGradient::Gradient(value));
417                } else {
418                    cx.style
419                        .background_image
420                        .insert(entity, vec![ImageOrGradient::Gradient(value)]);
421                }
422
423                cx.needs_redraw(entity);
424            });
425        });
426
427        self
428    }
429
430    // Background Properties
431    modifier!(
432        /// Sets the background color of the view.
433        background_color,
434        Color,
435        SystemFlags::REDRAW
436    );
437
438    /// Set the background image of the view.
439    fn background_image<'i, U: Into<BackgroundImage<'i>>>(mut self, value: impl Res<U>) -> Self {
440        let entity = self.entity();
441        let current = self.current();
442        self.context().with_current(current, |cx| {
443            value.set_or_bind(cx, move |cx, val| {
444                let image = val.get_value(cx).into();
445                let image = match image {
446                    BackgroundImage::Gradient(gradient) => {
447                        Some(ImageOrGradient::Gradient(*gradient))
448                    }
449                    BackgroundImage::Url(url) => Some(ImageOrGradient::Image(url.url.to_string())),
450
451                    _ => None,
452                };
453
454                if let Some(image) = image {
455                    cx.style.background_image.insert(entity, vec![image]);
456                }
457
458                cx.needs_redraw(entity);
459            });
460        });
461
462        self
463    }
464
465    // Border Properties
466    fn border_width<U: Into<LengthOrPercentage>>(mut self, value: impl Res<U>) -> Self {
467        let entity = self.entity();
468        let _current = self.current();
469        value.set_or_bind(self.context(), move |cx, v| {
470            cx.style.border_width.insert(entity, v.get_value(cx).into());
471            cx.cache.path.remove(entity);
472            cx.style.system_flags |= SystemFlags::RELAYOUT | SystemFlags::REDRAW;
473            cx.set_system_flags(entity, SystemFlags::RELAYOUT | SystemFlags::REDRAW);
474        });
475
476        self
477    }
478
479    modifier!(
480        /// Sets the border color of the view.
481        border_color,
482        Color,
483        SystemFlags::REDRAW
484    );
485
486    modifier!(
487        /// Sets the border color of the view.
488        border_style,
489        BorderStyleKeyword,
490        SystemFlags::REDRAW
491    );
492
493    modifier!(
494        /// Sets the corner radius for the top-left corner of the view.
495        corner_top_left_radius,
496        LengthOrPercentage,
497        SystemFlags::REDRAW
498    );
499
500    modifier!(
501        /// Sets the corner radius for the top-right corner of the view.
502        corner_top_right_radius,
503        LengthOrPercentage,
504        SystemFlags::REDRAW
505    );
506
507    modifier!(
508        /// Sets the corner radius for the bottom-left corner of the view.
509        corner_bottom_left_radius,
510        LengthOrPercentage,
511        SystemFlags::REDRAW
512    );
513
514    modifier!(
515        /// Sets the corner radius for the bottom-right corner of the view.
516        corner_bottom_right_radius,
517        LengthOrPercentage,
518        SystemFlags::REDRAW
519    );
520
521    /// Sets the corner radius for all four corners of the view.
522    fn corner_radius<U: std::fmt::Debug + Into<CornerRadius>>(
523        mut self,
524        value: impl Res<U>,
525    ) -> Self {
526        let entity = self.entity();
527        let current = self.current();
528        self.context().with_current(current, |cx| {
529            value.set_or_bind(cx, move |cx, v| {
530                let value = v.get_value(cx).into();
531                cx.style.corner_top_left_radius.insert(entity, value.top_left);
532                cx.style.corner_top_right_radius.insert(entity, value.top_right);
533                cx.style.corner_bottom_left_radius.insert(entity, value.bottom_left);
534                cx.style.corner_bottom_right_radius.insert(entity, value.bottom_right);
535
536                cx.needs_redraw(entity);
537            });
538        });
539
540        self
541    }
542
543    modifier!(
544        /// Sets the corner corner shape for the top-left corner of the view.
545        corner_top_left_shape,
546        CornerShape,
547        SystemFlags::REDRAW
548    );
549
550    modifier!(
551        /// Sets the corner corner shape for the top-right corner of the view.
552        corner_top_right_shape,
553        CornerShape,
554        SystemFlags::REDRAW
555    );
556
557    modifier!(
558        /// Sets the corner corner shape for the bottom-left corner of the view.
559        corner_bottom_left_shape,
560        CornerShape,
561        SystemFlags::REDRAW
562    );
563
564    modifier!(
565        /// Sets the corner corner shape for the bottom-right corner of the view.
566        corner_bottom_right_shape,
567        CornerShape,
568        SystemFlags::REDRAW
569    );
570
571    /// Sets the corner shape for all four corners of the view.
572    fn corner_shape<U: std::fmt::Debug + Into<Rect<CornerShape>>>(
573        mut self,
574        value: impl Res<U>,
575    ) -> Self {
576        let entity = self.entity();
577        let current = self.current();
578        self.context().with_current(current, |cx| {
579            value.set_or_bind(cx, move |cx, v| {
580                let value = v.get_value(cx).into();
581                cx.style.corner_top_left_shape.insert(entity, value.0);
582                cx.style.corner_top_right_shape.insert(entity, value.1);
583                cx.style.corner_bottom_right_shape.insert(entity, value.2);
584                cx.style.corner_bottom_left_shape.insert(entity, value.3);
585
586                cx.needs_redraw(entity);
587            });
588        });
589
590        self
591    }
592
593    modifier!(
594        /// Sets the corner smoothing for the top-left corner of the view.
595        corner_top_left_smoothing,
596        f32,
597        SystemFlags::REDRAW
598    );
599
600    modifier!(
601        /// Sets the corner smoothing for the top-right corner of the view.
602        corner_top_right_smoothing,
603        f32,
604        SystemFlags::REDRAW
605    );
606
607    modifier!(
608        /// Sets the corner smoothing for the bottom-left corner of the view.
609        corner_bottom_left_smoothing,
610        f32,
611        SystemFlags::REDRAW
612    );
613
614    modifier!(
615        /// Sets the corner smoothing for the bottom-right corner of the view.
616        corner_bottom_right_smoothing,
617        f32,
618        SystemFlags::REDRAW
619    );
620
621    /// Sets the corner smoothing for all four corners of the view.
622    fn corner_smoothing<U: std::fmt::Debug + Into<Rect<f32>>>(
623        mut self,
624        value: impl Res<U>,
625    ) -> Self {
626        let entity = self.entity();
627        let current = self.current();
628        self.context().with_current(current, |cx| {
629            value.set_or_bind(cx, move |cx, v| {
630                let value = v.get_value(cx).into();
631                cx.style.corner_top_left_smoothing.insert(entity, value.0);
632                cx.style.corner_top_right_smoothing.insert(entity, value.1);
633                cx.style.corner_bottom_left_smoothing.insert(entity, value.2);
634                cx.style.corner_bottom_right_smoothing.insert(entity, value.3);
635
636                cx.needs_redraw(entity);
637            });
638        });
639
640        self
641    }
642
643    // Outline Properties
644    modifier!(
645        /// Sets the outline width of the view.
646        outline_width,
647        LengthOrPercentage,
648        SystemFlags::REDRAW
649    );
650
651    modifier!(
652        /// Sets the outline color of the view.
653        outline_color,
654        Color,
655        SystemFlags::REDRAW
656    );
657
658    modifier!(
659        /// Sets the outline offset of the view.
660        outline_offset,
661        LengthOrPercentage,
662        SystemFlags::REDRAW
663    );
664
665    modifier!(
666        /// Overrides the fill color of SVG images.
667        fill,
668        Color,
669        SystemFlags::REDRAW
670    );
671
672    // Cursor Icon
673    modifier!(
674        /// Sets the mouse cursor used when the view is hovered.
675        cursor,
676        CursorIcon,
677        SystemFlags::empty()
678    );
679
680    /// Sets whether the view can be become the target of pointer events.
681    fn pointer_events<U: Into<PointerEvents>>(mut self, value: impl Res<U>) -> Self {
682        let entity = self.entity();
683        let current = self.current();
684        self.context().with_current(current, |cx| {
685            value.set_or_bind(cx, move |cx, v| {
686                let value = v.get_value(cx).into();
687                cx.style.pointer_events.insert(entity, value);
688            });
689        });
690
691        self
692    }
693
694    /// Sets the transform of the view with a list of transform functions.
695    fn transform<U: Into<Vec<Transform>>>(mut self, value: impl Res<U>) -> Self {
696        let entity = self.entity();
697        let current = self.current();
698        self.context().with_current(current, |cx| {
699            value.set_or_bind(cx, move |cx, v| {
700                let value = v.get_value(cx).into();
701                cx.style.transform.insert(entity, value);
702                cx.needs_retransform(entity);
703                cx.needs_redraw(entity);
704            });
705        });
706
707        self
708    }
709
710    /// Sets the transform origin of the the view.
711    fn transform_origin<U: Into<Position>>(mut self, value: impl Res<U>) -> Self {
712        let entity = self.entity();
713        let current = self.current();
714        self.context().with_current(current, |cx| {
715            value.set_or_bind(cx, move |cx, v| {
716                let value = v.get_value(cx).into();
717                let x = value.x.to_length_or_percentage();
718                let y = value.y.to_length_or_percentage();
719                cx.style.transform_origin.insert(entity, Translate { x, y });
720                cx.needs_retransform(entity);
721                cx.needs_redraw(entity);
722            });
723        });
724
725        self
726    }
727
728    // Translate
729    modifier!(
730        /// Sets the translation offset of the view.
731        ///
732        /// Translation applies to the rendered view and does not affect layout.
733        translate,
734        Translate,
735        SystemFlags::RETRANSFORM | SystemFlags::REDRAW
736    );
737
738    // Rotate
739    modifier!(
740        /// Sets the angle of rotation for the view.
741        ///
742        /// Rotation applies to the rendered view and does not affect layout.
743        rotate,
744        Angle,
745        SystemFlags::RETRANSFORM | SystemFlags::REDRAW
746    );
747
748    // Scale
749    modifier!(
750        /// Sets the scale of the view.
751        ///
752        /// Scale applies to the rendered view and does not affect layout.
753        scale,
754        Scale,
755        SystemFlags::RETRANSFORM | SystemFlags::REDRAW
756    );
757}
758
759impl<V: View> StyleModifiers for Handle<'_, V> {}
760
761/// A builder for constructing linear gradients.
762#[derive(Debug, Clone)]
763pub struct LinearGradientBuilder {
764    direction: LineDirection,
765    stops: Vec<ColorStop<LengthOrPercentage>>,
766}
767
768impl Default for LinearGradientBuilder {
769    fn default() -> Self {
770        Self::new()
771    }
772}
773
774impl LinearGradientBuilder {
775    /// Creates a new [LinearGradientBuilder].
776    pub fn new() -> Self {
777        LinearGradientBuilder { direction: LineDirection::default(), stops: Vec::new() }
778    }
779
780    /// Set the direction of the linear gradient.
781    pub fn with_direction(direction: impl Into<LineDirection>) -> Self {
782        LinearGradientBuilder { direction: direction.into(), stops: Vec::new() }
783    }
784
785    fn build(self) -> Gradient {
786        Gradient::Linear(LinearGradient { direction: self.direction, stops: self.stops })
787    }
788
789    /// Add a color stop to the linear gradient.
790    pub fn add_stop(mut self, stop: impl Into<ColorStop<LengthOrPercentage>>) -> Self {
791        self.stops.push(stop.into());
792
793        self
794    }
795}
796
797impl From<LinearGradientBuilder> for Gradient {
798    fn from(value: LinearGradientBuilder) -> Self {
799        value.build()
800    }
801}
802
803/// A builder for constructing a shadow.
804#[derive(Debug, Clone)]
805pub struct ShadowBuilder {
806    shadow: Shadow,
807}
808
809impl Default for ShadowBuilder {
810    fn default() -> Self {
811        Self::new()
812    }
813}
814
815impl ShadowBuilder {
816    /// Creates a new [ShadowBuilder].
817    pub fn new() -> Self {
818        Self { shadow: Shadow::default() }
819    }
820
821    fn build(self) -> Shadow {
822        self.shadow
823    }
824
825    /// Sets the horizontal offset of the shadow.
826    pub fn x_offset(mut self, offset: impl Into<Length>) -> Self {
827        self.shadow.x_offset = offset.into();
828
829        self
830    }
831
832    /// Set the vertical offset of the shadow.
833    pub fn y_offset(mut self, offset: impl Into<Length>) -> Self {
834        self.shadow.y_offset = offset.into();
835
836        self
837    }
838
839    /// Sets the blur radius of the shadow.
840    pub fn blur(mut self, radius: Length) -> Self {
841        self.shadow.blur_radius = Some(radius);
842
843        self
844    }
845
846    /// Sets the spread amount of the shadow.
847    pub fn spread(mut self, radius: Length) -> Self {
848        self.shadow.spread_radius = Some(radius);
849
850        self
851    }
852
853    /// Sets the color of the shadow.
854    pub fn color(mut self, color: Color) -> Self {
855        self.shadow.color = Some(color);
856
857        self
858    }
859
860    /// Sets whether the shadow should be inset.
861    pub fn inset(mut self) -> Self {
862        self.shadow.inset = true;
863
864        self
865    }
866}
867
868impl From<ShadowBuilder> for Shadow {
869    fn from(value: ShadowBuilder) -> Self {
870        value.build()
871    }
872}