1use vizia_style::{ColorStop, CornerRadius};
2
3use super::internal;
4use crate::prelude::*;
5
6pub trait StyleModifiers: internal::Modifiable {
8 fn id(mut self, id: impl Into<String>) -> Self {
27 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 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 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 fn checked<U: Into<bool>>(mut self, state: impl Res<U>) -> Self {
93 let entity = self.entity();
94 let current = self.current();
95 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 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 }
130
131 cx.needs_restyle(entity);
132 });
133 });
134
135 self
136 }
137
138 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.with_current(entity, |cx| cx.focus_with_visibility(visibility));
155 cx.needs_restyle(entity);
156 }
157 });
158 });
159 });
160
161 self
162 }
163
164 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 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 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 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 disabled,
241 bool,
242 SystemFlags::RESTYLE | SystemFlags::REACCESS
243 );
244
245 modifier!(
246 display,
250 Display,
251 SystemFlags::RELAYOUT | SystemFlags::REDRAW | SystemFlags::REFLOW
252 );
253
254 modifier!(
255 visibility,
259 Visibility,
260 SystemFlags::REDRAW
261 );
262
263 modifier!(
264 opacity,
268 Opacity,
269 SystemFlags::REDRAW
270 );
271
272 fn z_index<U: Into<i32>>(mut self, value: impl Res<U>) -> Self {
277 let entity = self.entity();
278 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 self
286 }
287
288 modifier!(
289 ignore_clipping,
293 bool,
294 SystemFlags::RECLIP | SystemFlags::REDRAW
295 );
296
297 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 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 overflowx,
335 Overflow,
336 SystemFlags::RECLIP | SystemFlags::REDRAW
337 );
338
339 modifier!(
340 overflowy,
344 Overflow,
345 SystemFlags::RECLIP | SystemFlags::REDRAW
346 );
347
348 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 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 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 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 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 modifier!(
441 background_color,
443 Color,
444 SystemFlags::REDRAW
445 );
446
447 modifier!(
448 background_position,
450 Vec<Position>,
451 SystemFlags::REDRAW
452 );
453
454 modifier!(
455 background_size,
457 Vec<BackgroundSize>,
458 SystemFlags::REDRAW
459 );
460
461 modifier!(
462 background_repeat,
464 Vec<BackgroundRepeat>,
465 SystemFlags::REDRAW
466 );
467
468 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 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 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 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 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 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 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 border_top_color,
578 Color,
579 SystemFlags::REDRAW
580 );
581
582 modifier!(
583 border_right_color,
585 Color,
586 SystemFlags::REDRAW
587 );
588
589 modifier!(
590 border_bottom_color,
592 Color,
593 SystemFlags::REDRAW
594 );
595
596 modifier!(
597 border_left_color,
599 Color,
600 SystemFlags::REDRAW
601 );
602
603 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 border_top_style,
620 BorderStyleKeyword,
621 SystemFlags::REDRAW
622 );
623
624 modifier!(
625 border_right_style,
627 BorderStyleKeyword,
628 SystemFlags::REDRAW
629 );
630
631 modifier!(
632 border_bottom_style,
634 BorderStyleKeyword,
635 SystemFlags::REDRAW
636 );
637
638 modifier!(
639 border_left_style,
641 BorderStyleKeyword,
642 SystemFlags::REDRAW
643 );
644
645 modifier!(
646 corner_top_left_radius,
648 LengthOrPercentage,
649 SystemFlags::REDRAW
650 );
651
652 modifier!(
653 corner_top_right_radius,
655 LengthOrPercentage,
656 SystemFlags::REDRAW
657 );
658
659 modifier!(
660 corner_bottom_left_radius,
662 LengthOrPercentage,
663 SystemFlags::REDRAW
664 );
665
666 modifier!(
667 corner_bottom_right_radius,
669 LengthOrPercentage,
670 SystemFlags::REDRAW
671 );
672
673 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!(
697 outline_width,
699 LengthOrPercentage,
700 SystemFlags::REDRAW
701 );
702
703 modifier!(
704 outline_color,
706 Color,
707 SystemFlags::REDRAW
708 );
709
710 modifier!(
711 outline_offset,
713 LengthOrPercentage,
714 SystemFlags::REDRAW
715 );
716
717 modifier!(
718 fill,
720 Color,
721 SystemFlags::REDRAW
722 );
723
724 modifier!(
726 cursor,
728 CursorIcon,
729 SystemFlags::empty()
730 );
731
732 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 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 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 modifier!(
782 translate,
786 Translate,
787 SystemFlags::RETRANSFORM | SystemFlags::REDRAW
788 );
789
790 modifier!(
792 rotate,
796 Angle,
797 SystemFlags::RETRANSFORM | SystemFlags::REDRAW
798 );
799
800 modifier!(
802 scale,
806 Scale,
807 SystemFlags::RETRANSFORM | SystemFlags::REDRAW
808 );
809}
810
811impl<V: View> StyleModifiers for Handle<'_, V> {}
812
813#[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 pub fn new() -> Self {
829 LinearGradientBuilder { direction: LineDirection::default(), stops: Vec::new() }
830 }
831
832 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 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#[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 pub fn new() -> Self {
870 Self { shadow: Shadow::default() }
871 }
872
873 fn build(self) -> Shadow {
874 self.shadow
875 }
876
877 pub fn x_offset(mut self, offset: impl Into<Length>) -> Self {
879 self.shadow.x_offset = offset.into();
880
881 self
882 }
883
884 pub fn y_offset(mut self, offset: impl Into<Length>) -> Self {
886 self.shadow.y_offset = offset.into();
887
888 self
889 }
890
891 pub fn blur(mut self, radius: Length) -> Self {
893 self.shadow.blur_radius = Some(radius);
894
895 self
896 }
897
898 pub fn spread(mut self, radius: Length) -> Self {
900 self.shadow.spread_radius = Some(radius);
901
902 self
903 }
904
905 pub fn color(mut self, color: Color) -> Self {
907 self.shadow.color = Some(color);
908
909 self
910 }
911
912 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}