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.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    modifier!(
696        /// Sets the corner corner shape for the top-left corner of the view.
697        corner_top_left_shape,
698        CornerShape,
699        SystemFlags::REDRAW
700    );
701
702    modifier!(
703        /// Sets the corner corner shape for the top-right corner of the view.
704        corner_top_right_shape,
705        CornerShape,
706        SystemFlags::REDRAW
707    );
708
709    modifier!(
710        /// Sets the corner corner shape for the bottom-left corner of the view.
711        corner_bottom_left_shape,
712        CornerShape,
713        SystemFlags::REDRAW
714    );
715
716    modifier!(
717        /// Sets the corner corner shape for the bottom-right corner of the view.
718        corner_bottom_right_shape,
719        CornerShape,
720        SystemFlags::REDRAW
721    );
722
723    /// Sets the corner shape for all four corners of the view.
724    fn corner_shape<U: std::fmt::Debug + Into<Rect<CornerShape>>>(
725        mut self,
726        value: impl Res<U>,
727    ) -> 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                cx.style.corner_top_left_shape.insert(entity, value.0);
734                cx.style.corner_top_right_shape.insert(entity, value.1);
735                cx.style.corner_bottom_right_shape.insert(entity, value.2);
736                cx.style.corner_bottom_left_shape.insert(entity, value.3);
737
738                cx.needs_redraw(entity);
739            });
740        });
741
742        self
743    }
744
745    modifier!(
746        /// Sets the corner smoothing for the top-left corner of the view.
747        corner_top_left_smoothing,
748        f32,
749        SystemFlags::REDRAW
750    );
751
752    modifier!(
753        /// Sets the corner smoothing for the top-right corner of the view.
754        corner_top_right_smoothing,
755        f32,
756        SystemFlags::REDRAW
757    );
758
759    modifier!(
760        /// Sets the corner smoothing for the bottom-left corner of the view.
761        corner_bottom_left_smoothing,
762        f32,
763        SystemFlags::REDRAW
764    );
765
766    modifier!(
767        /// Sets the corner smoothing for the bottom-right corner of the view.
768        corner_bottom_right_smoothing,
769        f32,
770        SystemFlags::REDRAW
771    );
772
773    /// Sets the corner smoothing for all four corners of the view.
774    fn corner_smoothing<U: std::fmt::Debug + Into<Rect<f32>>>(
775        mut self,
776        value: impl Res<U>,
777    ) -> Self {
778        let entity = self.entity();
779        let current = self.current();
780        self.context().with_current(current, |cx| {
781            value.set_or_bind(cx, move |cx, v| {
782                let value = v.get_value(cx).into();
783                cx.style.corner_top_left_smoothing.insert(entity, value.0);
784                cx.style.corner_top_right_smoothing.insert(entity, value.1);
785                cx.style.corner_bottom_left_smoothing.insert(entity, value.2);
786                cx.style.corner_bottom_right_smoothing.insert(entity, value.3);
787
788                cx.needs_redraw(entity);
789            });
790        });
791
792        self
793    }
794
795    // Outline Properties
796    modifier!(
797        /// Sets the outline width of the view.
798        outline_width,
799        LengthOrPercentage,
800        SystemFlags::REDRAW
801    );
802
803    modifier!(
804        /// Sets the outline color of the view.
805        outline_color,
806        Color,
807        SystemFlags::REDRAW
808    );
809
810    modifier!(
811        /// Sets the outline offset of the view.
812        outline_offset,
813        LengthOrPercentage,
814        SystemFlags::REDRAW
815    );
816
817    modifier!(
818        /// Overrides the fill color of SVG images.
819        fill,
820        Color,
821        SystemFlags::REDRAW
822    );
823
824    // Cursor Icon
825    modifier!(
826        /// Sets the mouse cursor used when the view is hovered.
827        cursor,
828        CursorIcon,
829        SystemFlags::empty()
830    );
831
832    /// Sets whether the view can be become the target of pointer events.
833    fn pointer_events<U: Into<PointerEvents>>(mut self, value: impl Res<U>) -> Self {
834        let entity = self.entity();
835        let current = self.current();
836        self.context().with_current(current, |cx| {
837            value.set_or_bind(cx, move |cx, v| {
838                let value = v.get_value(cx).into();
839                cx.style.pointer_events.insert(entity, value);
840            });
841        });
842
843        self
844    }
845
846    /// Sets the transform of the view with a list of transform functions.
847    fn transform<U: Into<Vec<Transform>>>(mut self, value: impl Res<U>) -> Self {
848        let entity = self.entity();
849        let current = self.current();
850        self.context().with_current(current, |cx| {
851            value.set_or_bind(cx, move |cx, v| {
852                let value = v.get_value(cx).into();
853                cx.style.transform.insert(entity, value);
854                cx.needs_retransform(entity);
855                cx.needs_redraw(entity);
856            });
857        });
858
859        self
860    }
861
862    /// Sets the transform origin of the the view.
863    fn transform_origin<U: Into<Position>>(mut self, value: impl Res<U>) -> Self {
864        let entity = self.entity();
865        let current = self.current();
866        self.context().with_current(current, |cx| {
867            value.set_or_bind(cx, move |cx, v| {
868                let value = v.get_value(cx).into();
869                let x = value.x.to_length_or_percentage();
870                let y = value.y.to_length_or_percentage();
871                cx.style.transform_origin.insert(entity, Translate { x, y });
872                cx.needs_retransform(entity);
873                cx.needs_redraw(entity);
874            });
875        });
876
877        self
878    }
879
880    // Translate
881    modifier!(
882        /// Sets the translation offset of the view.
883        ///
884        /// Translation applies to the rendered view and does not affect layout.
885        translate,
886        Translate,
887        SystemFlags::RETRANSFORM | SystemFlags::REDRAW
888    );
889
890    // Rotate
891    modifier!(
892        /// Sets the angle of rotation for the view.
893        ///
894        /// Rotation applies to the rendered view and does not affect layout.
895        rotate,
896        Angle,
897        SystemFlags::RETRANSFORM | SystemFlags::REDRAW
898    );
899
900    // Scale
901    modifier!(
902        /// Sets the scale of the view.
903        ///
904        /// Scale applies to the rendered view and does not affect layout.
905        scale,
906        Scale,
907        SystemFlags::RETRANSFORM | SystemFlags::REDRAW
908    );
909}
910
911impl<V: View> StyleModifiers for Handle<'_, V> {}
912
913/// A builder for constructing linear gradients.
914#[derive(Debug, Clone)]
915pub struct LinearGradientBuilder {
916    direction: LineDirection,
917    stops: Vec<ColorStop<LengthOrPercentage>>,
918}
919
920impl Default for LinearGradientBuilder {
921    fn default() -> Self {
922        Self::new()
923    }
924}
925
926impl LinearGradientBuilder {
927    /// Creates a new [LinearGradientBuilder].
928    pub fn new() -> Self {
929        LinearGradientBuilder { direction: LineDirection::default(), stops: Vec::new() }
930    }
931
932    /// Set the direction of the linear gradient.
933    pub fn with_direction(direction: impl Into<LineDirection>) -> Self {
934        LinearGradientBuilder { direction: direction.into(), stops: Vec::new() }
935    }
936
937    fn build(self) -> Gradient {
938        Gradient::Linear(LinearGradient { direction: self.direction, stops: self.stops })
939    }
940
941    /// Add a color stop to the linear gradient.
942    pub fn add_stop(mut self, stop: impl Into<ColorStop<LengthOrPercentage>>) -> Self {
943        self.stops.push(stop.into());
944
945        self
946    }
947}
948
949impl From<LinearGradientBuilder> for Gradient {
950    fn from(value: LinearGradientBuilder) -> Self {
951        value.build()
952    }
953}
954
955/// A builder for constructing a shadow.
956#[derive(Debug, Clone)]
957pub struct ShadowBuilder {
958    shadow: Shadow,
959}
960
961impl Default for ShadowBuilder {
962    fn default() -> Self {
963        Self::new()
964    }
965}
966
967impl ShadowBuilder {
968    /// Creates a new [ShadowBuilder].
969    pub fn new() -> Self {
970        Self { shadow: Shadow::default() }
971    }
972
973    fn build(self) -> Shadow {
974        self.shadow
975    }
976
977    /// Sets the horizontal offset of the shadow.
978    pub fn x_offset(mut self, offset: impl Into<Length>) -> Self {
979        self.shadow.x_offset = offset.into();
980
981        self
982    }
983
984    /// Set the vertical offset of the shadow.
985    pub fn y_offset(mut self, offset: impl Into<Length>) -> Self {
986        self.shadow.y_offset = offset.into();
987
988        self
989    }
990
991    /// Sets the blur radius of the shadow.
992    pub fn blur(mut self, radius: Length) -> Self {
993        self.shadow.blur_radius = Some(radius);
994
995        self
996    }
997
998    /// Sets the spread amount of the shadow.
999    pub fn spread(mut self, radius: Length) -> Self {
1000        self.shadow.spread_radius = Some(radius);
1001
1002        self
1003    }
1004
1005    /// Sets the color of the shadow.
1006    pub fn color(mut self, color: Color) -> Self {
1007        self.shadow.color = Some(color);
1008
1009        self
1010    }
1011
1012    /// Sets whether the shadow should be inset.
1013    pub fn inset(mut self) -> Self {
1014        self.shadow.inset = true;
1015
1016        self
1017    }
1018}
1019
1020impl From<ShadowBuilder> for Shadow {
1021    fn from(value: ShadowBuilder) -> Self {
1022        value.build()
1023    }
1024}