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 | SystemFlags::REFLOW
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    modifier!(
289        /// Sets whether the view should ignore ancestor clipping paths when drawing.
290        ///
291        /// This is useful for overlays such as popovers that need to escape overflow clipping.
292        ignore_clipping,
293        bool,
294        SystemFlags::RECLIP | SystemFlags::REDRAW
295    );
296
297    /// Sets the clip path for the the view.
298    fn clip_path<U: Into<ClipPath>>(mut self, value: impl Res<U>) -> Self {
299        let entity = self.entity();
300        let current = self.current();
301        self.context().with_current(current, |cx| {
302            value.set_or_bind(cx, move |cx, v| {
303                let value = v.get_value(cx).into();
304                cx.style.clip_path.insert(entity, value);
305                cx.needs_reclip(entity);
306                cx.needs_redraw(entity);
307            });
308        });
309
310        self
311    }
312
313    /// Sets the overflow behavior of the view in the horizontal and vertical directions simultaneously.
314    fn overflow<U: Into<Overflow>>(mut self, value: impl Res<U>) -> Self {
315        let entity = self.entity();
316        let current = self.current();
317        self.context().with_current(current, |cx| {
318            value.set_or_bind(cx, move |cx, v| {
319                let value = v.get_value(cx).into();
320                cx.style.overflowx.insert(entity, value);
321                cx.style.overflowy.insert(entity, value);
322                cx.needs_reclip(entity);
323                cx.needs_redraw(entity);
324            });
325        });
326
327        self
328    }
329
330    modifier!(
331        /// Sets the overflow behavior of the view in the horizontal direction.
332        ///
333        /// The overflow behavior determines whether child views can render outside the bounds of their parent.
334        overflowx,
335        Overflow,
336        SystemFlags::RECLIP | SystemFlags::REDRAW
337    );
338
339    modifier!(
340        /// Sets the overflow behavior of the view in the vertical direction.
341        ///
342        /// The overflow behavior determines whether child views can render outside the bounds of their parent.
343        overflowy,
344        Overflow,
345        SystemFlags::RECLIP | SystemFlags::REDRAW
346    );
347
348    /// Sets the filter for the view.
349    fn filter<U: Into<Filter>>(mut self, value: impl Res<U>) -> Self {
350        let entity = self.entity();
351        let current = self.current();
352        self.context().with_current(current, |cx| {
353            value.set_or_bind(cx, move |cx, v| {
354                let value = v.get_value(cx).into();
355                cx.style.filter.insert(entity, value);
356
357                cx.needs_redraw(entity);
358            });
359        });
360
361        self
362    }
363
364    /// Sets the backdrop filter for the view.
365    fn backdrop_filter<U: Into<Filter>>(mut self, value: impl Res<U>) -> Self {
366        let entity = self.entity();
367        let current = self.current();
368        self.context().with_current(current, |cx| {
369            value.set_or_bind(cx, move |cx, v| {
370                let value = v.get_value(cx).into();
371                cx.style.backdrop_filter.insert(entity, value);
372
373                cx.needs_redraw(entity);
374            });
375        });
376
377        self
378    }
379
380    /// Add a shadow to the view.
381    fn shadow<U: Into<Shadow>>(mut self, value: impl Res<U>) -> Self {
382        let entity = self.entity();
383        let current = self.current();
384        self.context().with_current(current, |cx| {
385            value.set_or_bind(cx, move |cx, v| {
386                let value = v.get_value(cx).into();
387                if let Some(shadows) = cx.style.shadow.get_inline_mut(entity) {
388                    shadows.push(value);
389                } else {
390                    cx.style.shadow.insert(entity, vec![value]);
391                }
392
393                cx.needs_redraw(entity);
394            });
395        });
396
397        self
398    }
399
400    /// Set the shadows of the view.
401    fn shadows<U: Into<Vec<Shadow>>>(mut self, value: impl Res<U>) -> Self {
402        let entity = self.entity();
403        let current = self.current();
404        self.context().with_current(current, |cx| {
405            value.set_or_bind(cx, move |cx, v| {
406                let value = v.get_value(cx).into();
407
408                cx.style.shadow.insert(entity, value);
409
410                cx.needs_redraw(entity);
411            });
412        });
413
414        self
415    }
416
417    /// Set the background gradient of the view.
418    fn background_gradient<U: Into<Gradient>>(mut self, value: impl Res<U>) -> Self {
419        let entity = self.entity();
420        let current = self.current();
421        self.context().with_current(current, |cx| {
422            value.set_or_bind(cx, move |cx, v| {
423                let value = v.get_value(cx).into();
424                if let Some(background_images) = cx.style.background_image.get_inline_mut(entity) {
425                    background_images.push(ImageOrGradient::Gradient(value));
426                } else {
427                    cx.style
428                        .background_image
429                        .insert(entity, vec![ImageOrGradient::Gradient(value)]);
430                }
431
432                cx.needs_redraw(entity);
433            });
434        });
435
436        self
437    }
438
439    // Background Properties
440    modifier!(
441        /// Sets the background color of the view.
442        background_color,
443        Color,
444        SystemFlags::REDRAW
445    );
446
447    modifier!(
448        /// Sets the background size of the view.
449        background_size,
450        Vec<BackgroundSize>,
451        SystemFlags::REDRAW
452    );
453
454    /// Set the background image of the view.
455    fn background_image<'i, U: Into<BackgroundImage<'i>>>(mut self, value: impl Res<U>) -> Self {
456        let entity = self.entity();
457        let current = self.current();
458        self.context().with_current(current, |cx| {
459            value.set_or_bind(cx, move |cx, val| {
460                let image = val.get_value(cx).into();
461                let image = match image {
462                    BackgroundImage::Gradient(gradient) => {
463                        Some(ImageOrGradient::Gradient(*gradient))
464                    }
465                    BackgroundImage::Url(url) => Some(ImageOrGradient::Image(url.url.to_string())),
466
467                    _ => None,
468                };
469
470                if let Some(image) = image {
471                    cx.style.background_image.insert(entity, vec![image]);
472                }
473
474                cx.needs_redraw(entity);
475            });
476        });
477
478        self
479    }
480
481    // Border Properties
482    fn border_width<U: Into<LengthOrPercentage>>(mut self, value: impl Res<U>) -> Self {
483        let entity = self.entity();
484        let _current = self.current();
485        value.set_or_bind(self.context(), move |cx, v| {
486            cx.style.border_width.insert(entity, v.get_value(cx).into());
487            cx.cache.path.remove(entity);
488            cx.style.system_flags |= SystemFlags::RELAYOUT | SystemFlags::REDRAW;
489            cx.set_system_flags(entity, SystemFlags::RELAYOUT | SystemFlags::REDRAW);
490        });
491
492        self
493    }
494
495    modifier!(
496        /// Sets the border color of the view.
497        border_color,
498        Color,
499        SystemFlags::REDRAW
500    );
501
502    modifier!(
503        /// Sets the border color of the view.
504        border_style,
505        BorderStyleKeyword,
506        SystemFlags::REDRAW
507    );
508
509    modifier!(
510        /// Sets the corner radius for the top-left corner of the view.
511        corner_top_left_radius,
512        LengthOrPercentage,
513        SystemFlags::REDRAW
514    );
515
516    modifier!(
517        /// Sets the corner radius for the top-right corner of the view.
518        corner_top_right_radius,
519        LengthOrPercentage,
520        SystemFlags::REDRAW
521    );
522
523    modifier!(
524        /// Sets the corner radius for the bottom-left corner of the view.
525        corner_bottom_left_radius,
526        LengthOrPercentage,
527        SystemFlags::REDRAW
528    );
529
530    modifier!(
531        /// Sets the corner radius for the bottom-right corner of the view.
532        corner_bottom_right_radius,
533        LengthOrPercentage,
534        SystemFlags::REDRAW
535    );
536
537    /// Sets the corner radius for all four corners of the view.
538    fn corner_radius<U: std::fmt::Debug + Into<CornerRadius>>(
539        mut self,
540        value: impl Res<U>,
541    ) -> Self {
542        let entity = self.entity();
543        let current = self.current();
544        self.context().with_current(current, |cx| {
545            value.set_or_bind(cx, move |cx, v| {
546                let value = v.get_value(cx).into();
547                cx.style.corner_top_left_radius.insert(entity, value.top_left);
548                cx.style.corner_top_right_radius.insert(entity, value.top_right);
549                cx.style.corner_bottom_left_radius.insert(entity, value.bottom_left);
550                cx.style.corner_bottom_right_radius.insert(entity, value.bottom_right);
551
552                cx.needs_redraw(entity);
553            });
554        });
555
556        self
557    }
558
559    modifier!(
560        /// Sets the corner corner shape for the top-left corner of the view.
561        corner_top_left_shape,
562        CornerShape,
563        SystemFlags::REDRAW
564    );
565
566    modifier!(
567        /// Sets the corner corner shape for the top-right corner of the view.
568        corner_top_right_shape,
569        CornerShape,
570        SystemFlags::REDRAW
571    );
572
573    modifier!(
574        /// Sets the corner corner shape for the bottom-left corner of the view.
575        corner_bottom_left_shape,
576        CornerShape,
577        SystemFlags::REDRAW
578    );
579
580    modifier!(
581        /// Sets the corner corner shape for the bottom-right corner of the view.
582        corner_bottom_right_shape,
583        CornerShape,
584        SystemFlags::REDRAW
585    );
586
587    /// Sets the corner shape for all four corners of the view.
588    fn corner_shape<U: std::fmt::Debug + Into<Rect<CornerShape>>>(
589        mut self,
590        value: impl Res<U>,
591    ) -> Self {
592        let entity = self.entity();
593        let current = self.current();
594        self.context().with_current(current, |cx| {
595            value.set_or_bind(cx, move |cx, v| {
596                let value = v.get_value(cx).into();
597                cx.style.corner_top_left_shape.insert(entity, value.0);
598                cx.style.corner_top_right_shape.insert(entity, value.1);
599                cx.style.corner_bottom_right_shape.insert(entity, value.2);
600                cx.style.corner_bottom_left_shape.insert(entity, value.3);
601
602                cx.needs_redraw(entity);
603            });
604        });
605
606        self
607    }
608
609    modifier!(
610        /// Sets the corner smoothing for the top-left corner of the view.
611        corner_top_left_smoothing,
612        f32,
613        SystemFlags::REDRAW
614    );
615
616    modifier!(
617        /// Sets the corner smoothing for the top-right corner of the view.
618        corner_top_right_smoothing,
619        f32,
620        SystemFlags::REDRAW
621    );
622
623    modifier!(
624        /// Sets the corner smoothing for the bottom-left corner of the view.
625        corner_bottom_left_smoothing,
626        f32,
627        SystemFlags::REDRAW
628    );
629
630    modifier!(
631        /// Sets the corner smoothing for the bottom-right corner of the view.
632        corner_bottom_right_smoothing,
633        f32,
634        SystemFlags::REDRAW
635    );
636
637    /// Sets the corner smoothing for all four corners of the view.
638    fn corner_smoothing<U: std::fmt::Debug + Into<Rect<f32>>>(
639        mut self,
640        value: impl Res<U>,
641    ) -> Self {
642        let entity = self.entity();
643        let current = self.current();
644        self.context().with_current(current, |cx| {
645            value.set_or_bind(cx, move |cx, v| {
646                let value = v.get_value(cx).into();
647                cx.style.corner_top_left_smoothing.insert(entity, value.0);
648                cx.style.corner_top_right_smoothing.insert(entity, value.1);
649                cx.style.corner_bottom_left_smoothing.insert(entity, value.2);
650                cx.style.corner_bottom_right_smoothing.insert(entity, value.3);
651
652                cx.needs_redraw(entity);
653            });
654        });
655
656        self
657    }
658
659    // Outline Properties
660    modifier!(
661        /// Sets the outline width of the view.
662        outline_width,
663        LengthOrPercentage,
664        SystemFlags::REDRAW
665    );
666
667    modifier!(
668        /// Sets the outline color of the view.
669        outline_color,
670        Color,
671        SystemFlags::REDRAW
672    );
673
674    modifier!(
675        /// Sets the outline offset of the view.
676        outline_offset,
677        LengthOrPercentage,
678        SystemFlags::REDRAW
679    );
680
681    modifier!(
682        /// Overrides the fill color of SVG images.
683        fill,
684        Color,
685        SystemFlags::REDRAW
686    );
687
688    // Cursor Icon
689    modifier!(
690        /// Sets the mouse cursor used when the view is hovered.
691        cursor,
692        CursorIcon,
693        SystemFlags::empty()
694    );
695
696    /// Sets whether the view can be become the target of pointer events.
697    fn pointer_events<U: Into<PointerEvents>>(mut self, value: impl Res<U>) -> Self {
698        let entity = self.entity();
699        let current = self.current();
700        self.context().with_current(current, |cx| {
701            value.set_or_bind(cx, move |cx, v| {
702                let value = v.get_value(cx).into();
703                cx.style.pointer_events.insert(entity, value);
704            });
705        });
706
707        self
708    }
709
710    /// Sets the transform of the view with a list of transform functions.
711    fn transform<U: Into<Vec<Transform>>>(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                cx.style.transform.insert(entity, value);
718                cx.needs_retransform(entity);
719                cx.needs_redraw(entity);
720            });
721        });
722
723        self
724    }
725
726    /// Sets the transform origin of the the view.
727    fn transform_origin<U: Into<Position>>(mut self, value: impl Res<U>) -> Self {
728        let entity = self.entity();
729        let current = self.current();
730        self.context().with_current(current, |cx| {
731            value.set_or_bind(cx, move |cx, v| {
732                let value = v.get_value(cx).into();
733                let x = value.x.to_length_or_percentage();
734                let y = value.y.to_length_or_percentage();
735                cx.style.transform_origin.insert(entity, Translate { x, y });
736                cx.needs_retransform(entity);
737                cx.needs_redraw(entity);
738            });
739        });
740
741        self
742    }
743
744    // Translate
745    modifier!(
746        /// Sets the translation offset of the view.
747        ///
748        /// Translation applies to the rendered view and does not affect layout.
749        translate,
750        Translate,
751        SystemFlags::RETRANSFORM | SystemFlags::REDRAW
752    );
753
754    // Rotate
755    modifier!(
756        /// Sets the angle of rotation for the view.
757        ///
758        /// Rotation applies to the rendered view and does not affect layout.
759        rotate,
760        Angle,
761        SystemFlags::RETRANSFORM | SystemFlags::REDRAW
762    );
763
764    // Scale
765    modifier!(
766        /// Sets the scale of the view.
767        ///
768        /// Scale applies to the rendered view and does not affect layout.
769        scale,
770        Scale,
771        SystemFlags::RETRANSFORM | SystemFlags::REDRAW
772    );
773}
774
775impl<V: View> StyleModifiers for Handle<'_, V> {}
776
777/// A builder for constructing linear gradients.
778#[derive(Debug, Clone)]
779pub struct LinearGradientBuilder {
780    direction: LineDirection,
781    stops: Vec<ColorStop<LengthOrPercentage>>,
782}
783
784impl Default for LinearGradientBuilder {
785    fn default() -> Self {
786        Self::new()
787    }
788}
789
790impl LinearGradientBuilder {
791    /// Creates a new [LinearGradientBuilder].
792    pub fn new() -> Self {
793        LinearGradientBuilder { direction: LineDirection::default(), stops: Vec::new() }
794    }
795
796    /// Set the direction of the linear gradient.
797    pub fn with_direction(direction: impl Into<LineDirection>) -> Self {
798        LinearGradientBuilder { direction: direction.into(), stops: Vec::new() }
799    }
800
801    fn build(self) -> Gradient {
802        Gradient::Linear(LinearGradient { direction: self.direction, stops: self.stops })
803    }
804
805    /// Add a color stop to the linear gradient.
806    pub fn add_stop(mut self, stop: impl Into<ColorStop<LengthOrPercentage>>) -> Self {
807        self.stops.push(stop.into());
808
809        self
810    }
811}
812
813impl From<LinearGradientBuilder> for Gradient {
814    fn from(value: LinearGradientBuilder) -> Self {
815        value.build()
816    }
817}
818
819/// A builder for constructing a shadow.
820#[derive(Debug, Clone)]
821pub struct ShadowBuilder {
822    shadow: Shadow,
823}
824
825impl Default for ShadowBuilder {
826    fn default() -> Self {
827        Self::new()
828    }
829}
830
831impl ShadowBuilder {
832    /// Creates a new [ShadowBuilder].
833    pub fn new() -> Self {
834        Self { shadow: Shadow::default() }
835    }
836
837    fn build(self) -> Shadow {
838        self.shadow
839    }
840
841    /// Sets the horizontal offset of the shadow.
842    pub fn x_offset(mut self, offset: impl Into<Length>) -> Self {
843        self.shadow.x_offset = offset.into();
844
845        self
846    }
847
848    /// Set the vertical offset of the shadow.
849    pub fn y_offset(mut self, offset: impl Into<Length>) -> Self {
850        self.shadow.y_offset = offset.into();
851
852        self
853    }
854
855    /// Sets the blur radius of the shadow.
856    pub fn blur(mut self, radius: Length) -> Self {
857        self.shadow.blur_radius = Some(radius);
858
859        self
860    }
861
862    /// Sets the spread amount of the shadow.
863    pub fn spread(mut self, radius: Length) -> Self {
864        self.shadow.spread_radius = Some(radius);
865
866        self
867    }
868
869    /// Sets the color of the shadow.
870    pub fn color(mut self, color: Color) -> Self {
871        self.shadow.color = Some(color);
872
873        self
874    }
875
876    /// Sets whether the shadow should be inset.
877    pub fn inset(mut self) -> Self {
878        self.shadow.inset = true;
879
880        self
881    }
882}
883
884impl From<ShadowBuilder> for Shadow {
885    fn from(value: ShadowBuilder) -> Self {
886        value.build()
887    }
888}