Skip to main content

vizia_core/modifiers/
style.rs

1use vizia_style::{ColorStop, CornerRadius};
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.with_current(entity, |cx| 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.with_current(entity, |cx| 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 position of the view.
449        background_position,
450        Vec<Position>,
451        SystemFlags::REDRAW
452    );
453
454    modifier!(
455        /// Sets the background size of the view.
456        background_size,
457        Vec<BackgroundSize>,
458        SystemFlags::REDRAW
459    );
460
461    modifier!(
462        /// Sets the background repeat mode of the view.
463        background_repeat,
464        Vec<BackgroundRepeat>,
465        SystemFlags::REDRAW
466    );
467
468    /// Set the background image of the view.
469    fn background_image<'i, U: Into<BackgroundImage<'i>>>(mut self, value: impl Res<U>) -> Self {
470        let entity = self.entity();
471        let current = self.current();
472        self.context().with_current(current, |cx| {
473            value.set_or_bind(cx, move |cx, val| {
474                let image = val.get_value(cx).into();
475                let image = match image {
476                    BackgroundImage::Gradient(gradient) => {
477                        Some(ImageOrGradient::Gradient(*gradient))
478                    }
479                    BackgroundImage::Url(url) => Some(ImageOrGradient::Image(url.url.to_string())),
480
481                    _ => None,
482                };
483
484                if let Some(image) = image {
485                    cx.style.background_image.insert(entity, vec![image]);
486                }
487
488                cx.needs_redraw(entity);
489            });
490        });
491
492        self
493    }
494
495    // Border Properties
496
497    /// Sets the border width for all four sides of the view.
498    fn border_width<U: Into<LengthOrPercentage>>(mut self, value: impl Res<U>) -> Self {
499        let entity = self.entity();
500        value.set_or_bind(self.context(), move |cx, v| {
501            let w: LengthOrPercentage = v.get_value(cx).into();
502            cx.style.border_top_width.insert(entity, w.clone());
503            cx.style.border_right_width.insert(entity, w.clone());
504            cx.style.border_bottom_width.insert(entity, w.clone());
505            cx.style.border_left_width.insert(entity, w);
506            cx.cache.path.remove(entity);
507            cx.style.system_flags |= SystemFlags::RELAYOUT | SystemFlags::REDRAW;
508            cx.set_system_flags(entity, SystemFlags::RELAYOUT | SystemFlags::REDRAW);
509        });
510        self
511    }
512
513    /// Sets the top border width of the view.
514    fn border_top_width<U: Into<LengthOrPercentage>>(mut self, value: impl Res<U>) -> Self {
515        let entity = self.entity();
516        value.set_or_bind(self.context(), move |cx, v| {
517            cx.style.border_top_width.insert(entity, v.get_value(cx).into());
518            cx.cache.path.remove(entity);
519            cx.style.system_flags |= SystemFlags::RELAYOUT | SystemFlags::REDRAW;
520            cx.set_system_flags(entity, SystemFlags::RELAYOUT | SystemFlags::REDRAW);
521        });
522        self
523    }
524
525    /// Sets the right border width of the view.
526    fn border_right_width<U: Into<LengthOrPercentage>>(mut self, value: impl Res<U>) -> Self {
527        let entity = self.entity();
528        value.set_or_bind(self.context(), move |cx, v| {
529            cx.style.border_right_width.insert(entity, v.get_value(cx).into());
530            cx.cache.path.remove(entity);
531            cx.style.system_flags |= SystemFlags::RELAYOUT | SystemFlags::REDRAW;
532            cx.set_system_flags(entity, SystemFlags::RELAYOUT | SystemFlags::REDRAW);
533        });
534        self
535    }
536
537    /// Sets the bottom border width of the view.
538    fn border_bottom_width<U: Into<LengthOrPercentage>>(mut self, value: impl Res<U>) -> Self {
539        let entity = self.entity();
540        value.set_or_bind(self.context(), move |cx, v| {
541            cx.style.border_bottom_width.insert(entity, v.get_value(cx).into());
542            cx.cache.path.remove(entity);
543            cx.style.system_flags |= SystemFlags::RELAYOUT | SystemFlags::REDRAW;
544            cx.set_system_flags(entity, SystemFlags::RELAYOUT | SystemFlags::REDRAW);
545        });
546        self
547    }
548
549    /// Sets the left border width of the view.
550    fn border_left_width<U: Into<LengthOrPercentage>>(mut self, value: impl Res<U>) -> Self {
551        let entity = self.entity();
552        value.set_or_bind(self.context(), move |cx, v| {
553            cx.style.border_left_width.insert(entity, v.get_value(cx).into());
554            cx.cache.path.remove(entity);
555            cx.style.system_flags |= SystemFlags::RELAYOUT | SystemFlags::REDRAW;
556            cx.set_system_flags(entity, SystemFlags::RELAYOUT | SystemFlags::REDRAW);
557        });
558        self
559    }
560
561    /// Sets the border color for all four sides of the view.
562    fn border_color(mut self, value: impl Res<Color>) -> Self {
563        let entity = self.entity();
564        value.set_or_bind(self.context(), move |cx, v| {
565            let c = v.get_value(cx);
566            cx.style.border_top_color.insert(entity, c);
567            cx.style.border_right_color.insert(entity, c);
568            cx.style.border_bottom_color.insert(entity, c);
569            cx.style.border_left_color.insert(entity, c);
570            cx.needs_redraw(entity);
571        });
572        self
573    }
574
575    modifier!(
576        /// Sets the top border color of the view.
577        border_top_color,
578        Color,
579        SystemFlags::REDRAW
580    );
581
582    modifier!(
583        /// Sets the right border color of the view.
584        border_right_color,
585        Color,
586        SystemFlags::REDRAW
587    );
588
589    modifier!(
590        /// Sets the bottom border color of the view.
591        border_bottom_color,
592        Color,
593        SystemFlags::REDRAW
594    );
595
596    modifier!(
597        /// Sets the left border color of the view.
598        border_left_color,
599        Color,
600        SystemFlags::REDRAW
601    );
602
603    /// Sets the border style for all four sides of the view.
604    fn border_style(mut self, value: impl Res<BorderStyleKeyword>) -> Self {
605        let entity = self.entity();
606        value.set_or_bind(self.context(), move |cx, v| {
607            let s = v.get_value(cx);
608            cx.style.border_top_style.insert(entity, s);
609            cx.style.border_right_style.insert(entity, s);
610            cx.style.border_bottom_style.insert(entity, s);
611            cx.style.border_left_style.insert(entity, s);
612            cx.needs_redraw(entity);
613        });
614        self
615    }
616
617    modifier!(
618        /// Sets the top border style of the view.
619        border_top_style,
620        BorderStyleKeyword,
621        SystemFlags::REDRAW
622    );
623
624    modifier!(
625        /// Sets the right border style of the view.
626        border_right_style,
627        BorderStyleKeyword,
628        SystemFlags::REDRAW
629    );
630
631    modifier!(
632        /// Sets the bottom border style of the view.
633        border_bottom_style,
634        BorderStyleKeyword,
635        SystemFlags::REDRAW
636    );
637
638    modifier!(
639        /// Sets the left border style of the view.
640        border_left_style,
641        BorderStyleKeyword,
642        SystemFlags::REDRAW
643    );
644
645    modifier!(
646        /// Sets the corner radius for the top-left corner of the view.
647        corner_top_left_radius,
648        LengthOrPercentage,
649        SystemFlags::REDRAW
650    );
651
652    modifier!(
653        /// Sets the corner radius for the top-right corner of the view.
654        corner_top_right_radius,
655        LengthOrPercentage,
656        SystemFlags::REDRAW
657    );
658
659    modifier!(
660        /// Sets the corner radius for the bottom-left corner of the view.
661        corner_bottom_left_radius,
662        LengthOrPercentage,
663        SystemFlags::REDRAW
664    );
665
666    modifier!(
667        /// Sets the corner radius for the bottom-right corner of the view.
668        corner_bottom_right_radius,
669        LengthOrPercentage,
670        SystemFlags::REDRAW
671    );
672
673    /// Sets the corner radius for all four corners of the view.
674    fn corner_radius<U: std::fmt::Debug + Into<CornerRadius>>(
675        mut self,
676        value: impl Res<U>,
677    ) -> Self {
678        let entity = self.entity();
679        let current = self.current();
680        self.context().with_current(current, |cx| {
681            value.set_or_bind(cx, move |cx, v| {
682                let value = v.get_value(cx).into();
683                cx.style.corner_top_left_radius.insert(entity, value.top_left);
684                cx.style.corner_top_right_radius.insert(entity, value.top_right);
685                cx.style.corner_bottom_left_radius.insert(entity, value.bottom_left);
686                cx.style.corner_bottom_right_radius.insert(entity, value.bottom_right);
687
688                cx.needs_redraw(entity);
689            });
690        });
691
692        self
693    }
694
695    // Outline Properties
696    modifier!(
697        /// Sets the outline width of the view.
698        outline_width,
699        LengthOrPercentage,
700        SystemFlags::REDRAW
701    );
702
703    modifier!(
704        /// Sets the outline color of the view.
705        outline_color,
706        Color,
707        SystemFlags::REDRAW
708    );
709
710    modifier!(
711        /// Sets the outline offset of the view.
712        outline_offset,
713        LengthOrPercentage,
714        SystemFlags::REDRAW
715    );
716
717    modifier!(
718        /// Overrides the fill color of SVG images.
719        fill,
720        Color,
721        SystemFlags::REDRAW
722    );
723
724    // Cursor Icon
725    modifier!(
726        /// Sets the mouse cursor used when the view is hovered.
727        cursor,
728        CursorIcon,
729        SystemFlags::empty()
730    );
731
732    /// Sets whether the view can be become the target of pointer events.
733    fn pointer_events<U: Into<PointerEvents>>(mut self, value: impl Res<U>) -> Self {
734        let entity = self.entity();
735        let current = self.current();
736        self.context().with_current(current, |cx| {
737            value.set_or_bind(cx, move |cx, v| {
738                let value = v.get_value(cx).into();
739                cx.style.pointer_events.insert(entity, value);
740            });
741        });
742
743        self
744    }
745
746    /// Sets the transform of the view with a list of transform functions.
747    fn transform<U: Into<Vec<Transform>>>(mut self, value: impl Res<U>) -> Self {
748        let entity = self.entity();
749        let current = self.current();
750        self.context().with_current(current, |cx| {
751            value.set_or_bind(cx, move |cx, v| {
752                let value = v.get_value(cx).into();
753                cx.style.transform.insert(entity, value);
754                cx.needs_retransform(entity);
755                cx.needs_redraw(entity);
756            });
757        });
758
759        self
760    }
761
762    /// Sets the transform origin of the the view.
763    fn transform_origin<U: Into<Position>>(mut self, value: impl Res<U>) -> Self {
764        let entity = self.entity();
765        let current = self.current();
766        self.context().with_current(current, |cx| {
767            value.set_or_bind(cx, move |cx, v| {
768                let value = v.get_value(cx).into();
769                let x = value.x.to_length_or_percentage();
770                let y = value.y.to_length_or_percentage();
771                cx.style.transform_origin.insert(entity, Translate { x, y });
772                cx.needs_retransform(entity);
773                cx.needs_redraw(entity);
774            });
775        });
776
777        self
778    }
779
780    // Translate
781    modifier!(
782        /// Sets the translation offset of the view.
783        ///
784        /// Translation applies to the rendered view and does not affect layout.
785        translate,
786        Translate,
787        SystemFlags::RETRANSFORM | SystemFlags::REDRAW
788    );
789
790    // Rotate
791    modifier!(
792        /// Sets the angle of rotation for the view.
793        ///
794        /// Rotation applies to the rendered view and does not affect layout.
795        rotate,
796        Angle,
797        SystemFlags::RETRANSFORM | SystemFlags::REDRAW
798    );
799
800    // Scale
801    modifier!(
802        /// Sets the scale of the view.
803        ///
804        /// Scale applies to the rendered view and does not affect layout.
805        scale,
806        Scale,
807        SystemFlags::RETRANSFORM | SystemFlags::REDRAW
808    );
809}
810
811impl<V: View> StyleModifiers for Handle<'_, V> {}
812
813/// A builder for constructing linear gradients.
814#[derive(Debug, Clone)]
815pub struct LinearGradientBuilder {
816    direction: LineDirection,
817    stops: Vec<ColorStop<LengthOrPercentage>>,
818}
819
820impl Default for LinearGradientBuilder {
821    fn default() -> Self {
822        Self::new()
823    }
824}
825
826impl LinearGradientBuilder {
827    /// Creates a new [LinearGradientBuilder].
828    pub fn new() -> Self {
829        LinearGradientBuilder { direction: LineDirection::default(), stops: Vec::new() }
830    }
831
832    /// Set the direction of the linear gradient.
833    pub fn with_direction(direction: impl Into<LineDirection>) -> Self {
834        LinearGradientBuilder { direction: direction.into(), stops: Vec::new() }
835    }
836
837    fn build(self) -> Gradient {
838        Gradient::Linear(LinearGradient { direction: self.direction, stops: self.stops })
839    }
840
841    /// Add a color stop to the linear gradient.
842    pub fn add_stop(mut self, stop: impl Into<ColorStop<LengthOrPercentage>>) -> Self {
843        self.stops.push(stop.into());
844
845        self
846    }
847}
848
849impl From<LinearGradientBuilder> for Gradient {
850    fn from(value: LinearGradientBuilder) -> Self {
851        value.build()
852    }
853}
854
855/// A builder for constructing a shadow.
856#[derive(Debug, Clone)]
857pub struct ShadowBuilder {
858    shadow: Shadow,
859}
860
861impl Default for ShadowBuilder {
862    fn default() -> Self {
863        Self::new()
864    }
865}
866
867impl ShadowBuilder {
868    /// Creates a new [ShadowBuilder].
869    pub fn new() -> Self {
870        Self { shadow: Shadow::default() }
871    }
872
873    fn build(self) -> Shadow {
874        self.shadow
875    }
876
877    /// Sets the horizontal offset of the shadow.
878    pub fn x_offset(mut self, offset: impl Into<Length>) -> Self {
879        self.shadow.x_offset = offset.into();
880
881        self
882    }
883
884    /// Set the vertical offset of the shadow.
885    pub fn y_offset(mut self, offset: impl Into<Length>) -> Self {
886        self.shadow.y_offset = offset.into();
887
888        self
889    }
890
891    /// Sets the blur radius of the shadow.
892    pub fn blur(mut self, radius: Length) -> Self {
893        self.shadow.blur_radius = Some(radius);
894
895        self
896    }
897
898    /// Sets the spread amount of the shadow.
899    pub fn spread(mut self, radius: Length) -> Self {
900        self.shadow.spread_radius = Some(radius);
901
902        self
903    }
904
905    /// Sets the color of the shadow.
906    pub fn color(mut self, color: Color) -> Self {
907        self.shadow.color = Some(color);
908
909        self
910    }
911
912    /// Sets whether the shadow should be inset.
913    pub fn inset(mut self) -> Self {
914        self.shadow.inset = true;
915
916        self
917    }
918}
919
920impl From<ShadowBuilder> for Shadow {
921    fn from(value: ShadowBuilder) -> Self {
922        value.build()
923    }
924}