1use vizia_style::{ColorStop, CornerRadius, Rect};
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.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.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
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 fn clip_path<U: Into<ClipPath>>(mut self, value: impl Res<U>) -> Self {
290 let entity = self.entity();
291 let current = self.current();
292 self.context().with_current(current, |cx| {
293 value.set_or_bind(cx, move |cx, v| {
294 let value = v.get_value(cx).into();
295 cx.style.clip_path.insert(entity, value);
296 cx.needs_reclip(entity);
297 cx.needs_redraw(entity);
298 });
299 });
300
301 self
302 }
303
304 fn overflow<U: Into<Overflow>>(mut self, value: impl Res<U>) -> Self {
306 let entity = self.entity();
307 let current = self.current();
308 self.context().with_current(current, |cx| {
309 value.set_or_bind(cx, move |cx, v| {
310 let value = v.get_value(cx).into();
311 cx.style.overflowx.insert(entity, value);
312 cx.style.overflowy.insert(entity, value);
313 cx.needs_reclip(entity);
314 cx.needs_redraw(entity);
315 });
316 });
317
318 self
319 }
320
321 modifier!(
322 overflowx,
326 Overflow,
327 SystemFlags::RECLIP | SystemFlags::REDRAW
328 );
329
330 modifier!(
331 overflowy,
335 Overflow,
336 SystemFlags::RECLIP | SystemFlags::REDRAW
337 );
338
339 fn filter<U: Into<Filter>>(mut self, value: impl Res<U>) -> Self {
341 let entity = self.entity();
342 let current = self.current();
343 self.context().with_current(current, |cx| {
344 value.set_or_bind(cx, move |cx, v| {
345 let value = v.get_value(cx).into();
346 cx.style.filter.insert(entity, value);
347
348 cx.needs_redraw(entity);
349 });
350 });
351
352 self
353 }
354
355 fn backdrop_filter<U: Into<Filter>>(mut self, value: impl Res<U>) -> Self {
357 let entity = self.entity();
358 let current = self.current();
359 self.context().with_current(current, |cx| {
360 value.set_or_bind(cx, move |cx, v| {
361 let value = v.get_value(cx).into();
362 cx.style.backdrop_filter.insert(entity, value);
363
364 cx.needs_redraw(entity);
365 });
366 });
367
368 self
369 }
370
371 fn shadow<U: Into<Shadow>>(mut self, value: impl Res<U>) -> Self {
373 let entity = self.entity();
374 let current = self.current();
375 self.context().with_current(current, |cx| {
376 value.set_or_bind(cx, move |cx, v| {
377 let value = v.get_value(cx).into();
378 if let Some(shadows) = cx.style.shadow.get_inline_mut(entity) {
379 shadows.push(value);
380 } else {
381 cx.style.shadow.insert(entity, vec![value]);
382 }
383
384 cx.needs_redraw(entity);
385 });
386 });
387
388 self
389 }
390
391 fn shadows<U: Into<Vec<Shadow>>>(mut self, value: impl Res<U>) -> Self {
393 let entity = self.entity();
394 let current = self.current();
395 self.context().with_current(current, |cx| {
396 value.set_or_bind(cx, move |cx, v| {
397 let value = v.get_value(cx).into();
398
399 cx.style.shadow.insert(entity, value);
400
401 cx.needs_redraw(entity);
402 });
403 });
404
405 self
406 }
407
408 fn background_gradient<U: Into<Gradient>>(mut self, value: impl Res<U>) -> Self {
410 let entity = self.entity();
411 let current = self.current();
412 self.context().with_current(current, |cx| {
413 value.set_or_bind(cx, move |cx, v| {
414 let value = v.get_value(cx).into();
415 if let Some(background_images) = cx.style.background_image.get_inline_mut(entity) {
416 background_images.push(ImageOrGradient::Gradient(value));
417 } else {
418 cx.style
419 .background_image
420 .insert(entity, vec![ImageOrGradient::Gradient(value)]);
421 }
422
423 cx.needs_redraw(entity);
424 });
425 });
426
427 self
428 }
429
430 modifier!(
432 background_color,
434 Color,
435 SystemFlags::REDRAW
436 );
437
438 fn background_image<'i, U: Into<BackgroundImage<'i>>>(mut self, value: impl Res<U>) -> Self {
440 let entity = self.entity();
441 let current = self.current();
442 self.context().with_current(current, |cx| {
443 value.set_or_bind(cx, move |cx, val| {
444 let image = val.get_value(cx).into();
445 let image = match image {
446 BackgroundImage::Gradient(gradient) => {
447 Some(ImageOrGradient::Gradient(*gradient))
448 }
449 BackgroundImage::Url(url) => Some(ImageOrGradient::Image(url.url.to_string())),
450
451 _ => None,
452 };
453
454 if let Some(image) = image {
455 cx.style.background_image.insert(entity, vec![image]);
456 }
457
458 cx.needs_redraw(entity);
459 });
460 });
461
462 self
463 }
464
465 fn border_width<U: Into<LengthOrPercentage>>(mut self, value: impl Res<U>) -> Self {
467 let entity = self.entity();
468 let _current = self.current();
469 value.set_or_bind(self.context(), move |cx, v| {
470 cx.style.border_width.insert(entity, v.get_value(cx).into());
471 cx.cache.path.remove(entity);
472 cx.style.system_flags |= SystemFlags::RELAYOUT | SystemFlags::REDRAW;
473 cx.set_system_flags(entity, SystemFlags::RELAYOUT | SystemFlags::REDRAW);
474 });
475
476 self
477 }
478
479 modifier!(
480 border_color,
482 Color,
483 SystemFlags::REDRAW
484 );
485
486 modifier!(
487 border_style,
489 BorderStyleKeyword,
490 SystemFlags::REDRAW
491 );
492
493 modifier!(
494 corner_top_left_radius,
496 LengthOrPercentage,
497 SystemFlags::REDRAW
498 );
499
500 modifier!(
501 corner_top_right_radius,
503 LengthOrPercentage,
504 SystemFlags::REDRAW
505 );
506
507 modifier!(
508 corner_bottom_left_radius,
510 LengthOrPercentage,
511 SystemFlags::REDRAW
512 );
513
514 modifier!(
515 corner_bottom_right_radius,
517 LengthOrPercentage,
518 SystemFlags::REDRAW
519 );
520
521 fn corner_radius<U: std::fmt::Debug + Into<CornerRadius>>(
523 mut self,
524 value: impl Res<U>,
525 ) -> Self {
526 let entity = self.entity();
527 let current = self.current();
528 self.context().with_current(current, |cx| {
529 value.set_or_bind(cx, move |cx, v| {
530 let value = v.get_value(cx).into();
531 cx.style.corner_top_left_radius.insert(entity, value.top_left);
532 cx.style.corner_top_right_radius.insert(entity, value.top_right);
533 cx.style.corner_bottom_left_radius.insert(entity, value.bottom_left);
534 cx.style.corner_bottom_right_radius.insert(entity, value.bottom_right);
535
536 cx.needs_redraw(entity);
537 });
538 });
539
540 self
541 }
542
543 modifier!(
544 corner_top_left_shape,
546 CornerShape,
547 SystemFlags::REDRAW
548 );
549
550 modifier!(
551 corner_top_right_shape,
553 CornerShape,
554 SystemFlags::REDRAW
555 );
556
557 modifier!(
558 corner_bottom_left_shape,
560 CornerShape,
561 SystemFlags::REDRAW
562 );
563
564 modifier!(
565 corner_bottom_right_shape,
567 CornerShape,
568 SystemFlags::REDRAW
569 );
570
571 fn corner_shape<U: std::fmt::Debug + Into<Rect<CornerShape>>>(
573 mut self,
574 value: impl Res<U>,
575 ) -> Self {
576 let entity = self.entity();
577 let current = self.current();
578 self.context().with_current(current, |cx| {
579 value.set_or_bind(cx, move |cx, v| {
580 let value = v.get_value(cx).into();
581 cx.style.corner_top_left_shape.insert(entity, value.0);
582 cx.style.corner_top_right_shape.insert(entity, value.1);
583 cx.style.corner_bottom_right_shape.insert(entity, value.2);
584 cx.style.corner_bottom_left_shape.insert(entity, value.3);
585
586 cx.needs_redraw(entity);
587 });
588 });
589
590 self
591 }
592
593 modifier!(
594 corner_top_left_smoothing,
596 f32,
597 SystemFlags::REDRAW
598 );
599
600 modifier!(
601 corner_top_right_smoothing,
603 f32,
604 SystemFlags::REDRAW
605 );
606
607 modifier!(
608 corner_bottom_left_smoothing,
610 f32,
611 SystemFlags::REDRAW
612 );
613
614 modifier!(
615 corner_bottom_right_smoothing,
617 f32,
618 SystemFlags::REDRAW
619 );
620
621 fn corner_smoothing<U: std::fmt::Debug + Into<Rect<f32>>>(
623 mut self,
624 value: impl Res<U>,
625 ) -> Self {
626 let entity = self.entity();
627 let current = self.current();
628 self.context().with_current(current, |cx| {
629 value.set_or_bind(cx, move |cx, v| {
630 let value = v.get_value(cx).into();
631 cx.style.corner_top_left_smoothing.insert(entity, value.0);
632 cx.style.corner_top_right_smoothing.insert(entity, value.1);
633 cx.style.corner_bottom_left_smoothing.insert(entity, value.2);
634 cx.style.corner_bottom_right_smoothing.insert(entity, value.3);
635
636 cx.needs_redraw(entity);
637 });
638 });
639
640 self
641 }
642
643 modifier!(
645 outline_width,
647 LengthOrPercentage,
648 SystemFlags::REDRAW
649 );
650
651 modifier!(
652 outline_color,
654 Color,
655 SystemFlags::REDRAW
656 );
657
658 modifier!(
659 outline_offset,
661 LengthOrPercentage,
662 SystemFlags::REDRAW
663 );
664
665 modifier!(
666 fill,
668 Color,
669 SystemFlags::REDRAW
670 );
671
672 modifier!(
674 cursor,
676 CursorIcon,
677 SystemFlags::empty()
678 );
679
680 fn pointer_events<U: Into<PointerEvents>>(mut self, value: impl Res<U>) -> Self {
682 let entity = self.entity();
683 let current = self.current();
684 self.context().with_current(current, |cx| {
685 value.set_or_bind(cx, move |cx, v| {
686 let value = v.get_value(cx).into();
687 cx.style.pointer_events.insert(entity, value);
688 });
689 });
690
691 self
692 }
693
694 fn transform<U: Into<Vec<Transform>>>(mut self, value: impl Res<U>) -> Self {
696 let entity = self.entity();
697 let current = self.current();
698 self.context().with_current(current, |cx| {
699 value.set_or_bind(cx, move |cx, v| {
700 let value = v.get_value(cx).into();
701 cx.style.transform.insert(entity, value);
702 cx.needs_retransform(entity);
703 cx.needs_redraw(entity);
704 });
705 });
706
707 self
708 }
709
710 fn transform_origin<U: Into<Position>>(mut self, value: impl Res<U>) -> Self {
712 let entity = self.entity();
713 let current = self.current();
714 self.context().with_current(current, |cx| {
715 value.set_or_bind(cx, move |cx, v| {
716 let value = v.get_value(cx).into();
717 let x = value.x.to_length_or_percentage();
718 let y = value.y.to_length_or_percentage();
719 cx.style.transform_origin.insert(entity, Translate { x, y });
720 cx.needs_retransform(entity);
721 cx.needs_redraw(entity);
722 });
723 });
724
725 self
726 }
727
728 modifier!(
730 translate,
734 Translate,
735 SystemFlags::RETRANSFORM | SystemFlags::REDRAW
736 );
737
738 modifier!(
740 rotate,
744 Angle,
745 SystemFlags::RETRANSFORM | SystemFlags::REDRAW
746 );
747
748 modifier!(
750 scale,
754 Scale,
755 SystemFlags::RETRANSFORM | SystemFlags::REDRAW
756 );
757}
758
759impl<V: View> StyleModifiers for Handle<'_, V> {}
760
761#[derive(Debug, Clone)]
763pub struct LinearGradientBuilder {
764 direction: LineDirection,
765 stops: Vec<ColorStop<LengthOrPercentage>>,
766}
767
768impl Default for LinearGradientBuilder {
769 fn default() -> Self {
770 Self::new()
771 }
772}
773
774impl LinearGradientBuilder {
775 pub fn new() -> Self {
777 LinearGradientBuilder { direction: LineDirection::default(), stops: Vec::new() }
778 }
779
780 pub fn with_direction(direction: impl Into<LineDirection>) -> Self {
782 LinearGradientBuilder { direction: direction.into(), stops: Vec::new() }
783 }
784
785 fn build(self) -> Gradient {
786 Gradient::Linear(LinearGradient { direction: self.direction, stops: self.stops })
787 }
788
789 pub fn add_stop(mut self, stop: impl Into<ColorStop<LengthOrPercentage>>) -> Self {
791 self.stops.push(stop.into());
792
793 self
794 }
795}
796
797impl From<LinearGradientBuilder> for Gradient {
798 fn from(value: LinearGradientBuilder) -> Self {
799 value.build()
800 }
801}
802
803#[derive(Debug, Clone)]
805pub struct ShadowBuilder {
806 shadow: Shadow,
807}
808
809impl Default for ShadowBuilder {
810 fn default() -> Self {
811 Self::new()
812 }
813}
814
815impl ShadowBuilder {
816 pub fn new() -> Self {
818 Self { shadow: Shadow::default() }
819 }
820
821 fn build(self) -> Shadow {
822 self.shadow
823 }
824
825 pub fn x_offset(mut self, offset: impl Into<Length>) -> Self {
827 self.shadow.x_offset = offset.into();
828
829 self
830 }
831
832 pub fn y_offset(mut self, offset: impl Into<Length>) -> Self {
834 self.shadow.y_offset = offset.into();
835
836 self
837 }
838
839 pub fn blur(mut self, radius: Length) -> Self {
841 self.shadow.blur_radius = Some(radius);
842
843 self
844 }
845
846 pub fn spread(mut self, radius: Length) -> Self {
848 self.shadow.spread_radius = Some(radius);
849
850 self
851 }
852
853 pub fn color(mut self, color: Color) -> Self {
855 self.shadow.color = Some(color);
856
857 self
858 }
859
860 pub fn inset(mut self) -> Self {
862 self.shadow.inset = true;
863
864 self
865 }
866}
867
868impl From<ShadowBuilder> for Shadow {
869 fn from(value: ShadowBuilder) -> Self {
870 value.build()
871 }
872}