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, entity, move |cx, applied| {
72 let applied = applied.get(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, entity, move |cx, val| {
102 let val = val.get(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 });
108 });
109
110 self
111 }
112
113 fn focused<U: Into<bool>>(mut self, state: impl Res<U>) -> Self {
118 let entity = self.entity();
119 let current = self.current();
120
121 self.context().with_current(current, |cx| {
122 state.set_or_bind(cx, entity, |cx, val| {
123 let val = val.get(cx).into();
124
125 if val {
126 cx.focus();
127 }
129
130 cx.needs_restyle(cx.current);
131 });
132 });
133
134 self
135 }
136
137 fn focused_with_visibility<U: Into<bool>>(
139 mut self,
140 focus: impl Res<U> + Copy + 'static,
141 visibility: impl Res<U> + Copy + 'static,
142 ) -> Self {
143 let entity = self.entity();
144 let current = self.current();
145
146 self.context().with_current(current, move |cx| {
147 focus.set_or_bind(cx, entity, move |cx, f| {
148 visibility.set_or_bind(cx, entity, move |cx, v| {
149 let focus = f.get(cx).into();
150 let visibility = v.get(cx).into();
151 if focus {
152 cx.focus_with_visibility(visibility);
154 cx.needs_restyle(cx.current);
155 }
156 });
157 });
158 });
159
160 self
161 }
162
163 fn read_only<U: Into<bool>>(mut self, state: impl Res<U>) -> Self {
165 let entity = self.entity();
166 let current = self.current();
167 self.context().with_current(current, |cx| {
168 state.set_or_bind(cx, entity, move |cx, val| {
169 let val = val.get(cx).into();
170 if let Some(pseudo_classes) = cx.style.pseudo_classes.get_mut(cx.current) {
171 pseudo_classes.set(PseudoClassFlags::READ_ONLY, val);
172 }
173
174 cx.needs_restyle(cx.current);
175 });
176 });
177
178 self
179 }
180
181 fn read_write<U: Into<bool>>(mut self, state: impl Res<U>) -> Self {
183 let entity = self.entity();
184 let current = self.current();
185 self.context().with_current(current, |cx| {
186 state.set_or_bind(cx, entity, move |cx, val| {
187 let val = val.get(cx).into();
188 if let Some(pseudo_classes) = cx.style.pseudo_classes.get_mut(cx.current) {
189 pseudo_classes.set(PseudoClassFlags::READ_WRITE, val);
190 }
191
192 cx.needs_restyle(cx.current);
193 });
194 });
195
196 self
197 }
198
199 fn placeholder_shown<U: Into<bool>>(mut self, state: impl Res<U>) -> Self {
201 let entity = self.entity();
202 let current = self.current();
203 self.context().with_current(current, |cx| {
204 state.set_or_bind(cx, entity, move |cx, val| {
205 let val = val.get(cx).into();
206 if let Some(pseudo_classes) = cx.style.pseudo_classes.get_mut(cx.current) {
207 pseudo_classes.set(PseudoClassFlags::PLACEHOLDER_SHOWN, val);
208 }
209
210 cx.needs_restyle(cx.current);
211 });
212 });
213
214 self
215 }
216
217 modifier!(
218 disabled,
222 bool,
223 SystemFlags::RESTYLE
224 );
225
226 modifier!(
227 display,
231 Display,
232 SystemFlags::RELAYOUT | SystemFlags::REDRAW
233 );
234
235 modifier!(
236 visibility,
240 Visibility,
241 SystemFlags::REDRAW
242 );
243
244 modifier!(
245 opacity,
249 Opacity,
250 SystemFlags::REDRAW
251 );
252
253 fn z_index<U: Into<i32>>(mut self, value: impl Res<U>) -> Self {
258 let entity = self.entity();
259 let cx = self.context();
261 let value = value.get(cx).into();
262 cx.style.z_index.insert(entity, value);
263 cx.needs_redraw(entity);
264 self
267 }
268
269 fn clip_path<U: Into<ClipPath>>(mut self, value: impl Res<U>) -> Self {
271 let entity = self.entity();
272 let current = self.current();
273 self.context().with_current(current, |cx| {
274 value.set_or_bind(cx, entity, move |cx, v| {
275 let value = v.get(cx).into();
276 cx.style.clip_path.insert(cx.current, value);
277
278 cx.needs_redraw(entity);
279 });
280 });
281
282 self
283 }
284
285 fn overflow<U: Into<Overflow>>(mut self, value: impl Res<U>) -> Self {
287 let entity = self.entity();
288 let current = self.current();
289 self.context().with_current(current, |cx| {
290 value.set_or_bind(cx, entity, move |cx, v| {
291 let value = v.get(cx).into();
292 cx.style.overflowx.insert(cx.current, value);
293 cx.style.overflowy.insert(cx.current, value);
294
295 cx.needs_redraw(entity);
296 });
297 });
298
299 self
300 }
301
302 modifier!(
303 overflowx,
307 Overflow,
308 SystemFlags::REDRAW
309 );
310
311 modifier!(
312 overflowy,
316 Overflow,
317 SystemFlags::REDRAW
318 );
319
320 fn backdrop_filter<U: Into<Filter>>(mut self, value: impl Res<U>) -> Self {
322 let entity = self.entity();
323 let current = self.current();
324 self.context().with_current(current, |cx| {
325 value.set_or_bind(cx, entity, move |cx, v| {
326 let value = v.get(cx).into();
327 cx.style.backdrop_filter.insert(cx.current, value);
328
329 cx.needs_redraw(entity);
330 });
331 });
332
333 self
334 }
335
336 fn shadow<U: Into<Shadow>>(mut self, value: impl Res<U>) -> Self {
338 let entity = self.entity();
339 let current = self.current();
340 self.context().with_current(current, |cx| {
341 value.set_or_bind(cx, entity, move |cx, v| {
342 let value = v.get(cx).into();
343 if let Some(shadows) = cx.style.shadow.get_inline_mut(cx.current) {
344 shadows.push(value);
345 } else {
346 cx.style.shadow.insert(cx.current, vec![value]);
347 }
348
349 cx.needs_redraw(entity);
350 });
351 });
352
353 self
354 }
355
356 fn shadows<U: Into<Vec<Shadow>>>(mut self, value: impl Res<U>) -> Self {
358 let entity = self.entity();
359 let current = self.current();
360 self.context().with_current(current, |cx| {
361 value.set_or_bind(cx, entity, move |cx, v| {
362 let value = v.get(cx).into();
363
364 cx.style.shadow.insert(cx.current, value);
365
366 cx.needs_redraw(entity);
367 });
368 });
369
370 self
371 }
372
373 fn background_gradient<U: Into<Gradient>>(mut self, value: impl Res<U>) -> Self {
375 let entity = self.entity();
376 let current = self.current();
377 self.context().with_current(current, |cx| {
378 value.set_or_bind(cx, entity, move |cx, v| {
379 let value = v.get(cx).into();
380 if let Some(background_images) =
381 cx.style.background_image.get_inline_mut(cx.current)
382 {
383 background_images.push(ImageOrGradient::Gradient(value));
384 } else {
385 cx.style
386 .background_image
387 .insert(cx.current, vec![ImageOrGradient::Gradient(value)]);
388 }
389
390 cx.needs_redraw(entity);
391 });
392 });
393
394 self
395 }
396
397 modifier!(
399 background_color,
401 Color,
402 SystemFlags::REDRAW
403 );
404
405 fn background_image<'i, U: Into<BackgroundImage<'i>>>(mut self, value: impl Res<U>) -> Self {
407 let entity = self.entity();
408 let current = self.current();
409 self.context().with_current(current, |cx| {
410 value.set_or_bind(cx, entity, move |cx, val| {
411 let image = val.get(cx).into();
412 let image = match image {
413 BackgroundImage::Gradient(gradient) => {
414 Some(ImageOrGradient::Gradient(*gradient))
415 }
416 BackgroundImage::Url(url) => Some(ImageOrGradient::Image(url.url.to_string())),
417
418 _ => None,
419 };
420
421 if let Some(image) = image {
422 cx.style.background_image.insert(cx.current, vec![image]);
423 }
424
425 cx.needs_redraw(entity);
426 });
427 });
428
429 self
430 }
431
432 fn border_width<U: Into<LengthOrPercentage>>(mut self, value: impl Res<U>) -> Self {
434 let entity = self.entity();
435 let current = self.current();
436 value.set_or_bind(self.context(), current, move |cx, v| {
437 cx.style.border_width.insert(entity, v.get(cx).into());
438 cx.cache.path.remove(entity);
439 cx.style.system_flags |= SystemFlags::RELAYOUT | SystemFlags::REDRAW;
440 cx.set_system_flags(entity, SystemFlags::RELAYOUT | SystemFlags::REDRAW);
441 });
442
443 self
444 }
445
446 modifier!(
447 border_color,
449 Color,
450 SystemFlags::REDRAW
451 );
452
453 modifier!(
454 border_style,
456 BorderStyleKeyword,
457 SystemFlags::REDRAW
458 );
459
460 modifier!(
461 corner_top_left_radius,
463 LengthOrPercentage,
464 SystemFlags::REDRAW
465 );
466
467 modifier!(
468 corner_top_right_radius,
470 LengthOrPercentage,
471 SystemFlags::REDRAW
472 );
473
474 modifier!(
475 corner_bottom_left_radius,
477 LengthOrPercentage,
478 SystemFlags::REDRAW
479 );
480
481 modifier!(
482 corner_bottom_right_radius,
484 LengthOrPercentage,
485 SystemFlags::REDRAW
486 );
487
488 fn corner_radius<U: std::fmt::Debug + Into<CornerRadius>>(
490 mut self,
491 value: impl Res<U>,
492 ) -> Self {
493 let entity = self.entity();
494 let current = self.current();
495 self.context().with_current(current, |cx| {
496 value.set_or_bind(cx, entity, move |cx, v| {
497 let value = v.get(cx).into();
498 cx.style.corner_top_left_radius.insert(cx.current, value.top_left);
499 cx.style.corner_top_right_radius.insert(cx.current, value.top_right);
500 cx.style.corner_bottom_left_radius.insert(cx.current, value.bottom_left);
501 cx.style.corner_bottom_right_radius.insert(cx.current, value.bottom_right);
502
503 cx.needs_redraw(entity);
504 });
505 });
506
507 self
508 }
509
510 modifier!(
511 corner_top_left_shape,
513 CornerShape,
514 SystemFlags::REDRAW
515 );
516
517 modifier!(
518 corner_top_right_shape,
520 CornerShape,
521 SystemFlags::REDRAW
522 );
523
524 modifier!(
525 corner_bottom_left_shape,
527 CornerShape,
528 SystemFlags::REDRAW
529 );
530
531 modifier!(
532 corner_bottom_right_shape,
534 CornerShape,
535 SystemFlags::REDRAW
536 );
537
538 fn corner_shape<U: std::fmt::Debug + Into<Rect<CornerShape>>>(
540 mut self,
541 value: impl Res<U>,
542 ) -> Self {
543 let entity = self.entity();
544 let current = self.current();
545 self.context().with_current(current, |cx| {
546 value.set_or_bind(cx, entity, move |cx, v| {
547 let value = v.get(cx).into();
548 cx.style.corner_top_left_shape.insert(cx.current, value.0);
549 cx.style.corner_top_right_shape.insert(cx.current, value.1);
550 cx.style.corner_bottom_right_shape.insert(cx.current, value.2);
551 cx.style.corner_bottom_left_shape.insert(cx.current, value.3);
552
553 cx.needs_redraw(entity);
554 });
555 });
556
557 self
558 }
559
560 modifier!(
561 corner_top_left_smoothing,
563 f32,
564 SystemFlags::REDRAW
565 );
566
567 modifier!(
568 corner_top_right_smoothing,
570 f32,
571 SystemFlags::REDRAW
572 );
573
574 modifier!(
575 corner_bottom_left_smoothing,
577 f32,
578 SystemFlags::REDRAW
579 );
580
581 modifier!(
582 corner_bottom_right_smoothing,
584 f32,
585 SystemFlags::REDRAW
586 );
587
588 fn corner_smoothing<U: std::fmt::Debug + Into<Rect<f32>>>(
590 mut self,
591 value: impl Res<U>,
592 ) -> Self {
593 let entity = self.entity();
594 let current = self.current();
595 self.context().with_current(current, |cx| {
596 value.set_or_bind(cx, entity, move |cx, v| {
597 let value = v.get(cx).into();
598 cx.style.corner_top_left_smoothing.insert(cx.current, value.0);
599 cx.style.corner_top_right_smoothing.insert(cx.current, value.1);
600 cx.style.corner_bottom_left_smoothing.insert(cx.current, value.2);
601 cx.style.corner_bottom_right_smoothing.insert(cx.current, value.3);
602
603 cx.needs_redraw(entity);
604 });
605 });
606
607 self
608 }
609
610 modifier!(
612 outline_width,
614 LengthOrPercentage,
615 SystemFlags::REDRAW
616 );
617
618 modifier!(
619 outline_color,
621 Color,
622 SystemFlags::REDRAW
623 );
624
625 modifier!(
626 outline_offset,
628 LengthOrPercentage,
629 SystemFlags::REDRAW
630 );
631
632 modifier!(
633 fill,
635 Color,
636 SystemFlags::REDRAW
637 );
638
639 modifier!(
641 cursor,
643 CursorIcon,
644 SystemFlags::empty()
645 );
646
647 fn pointer_events<U: Into<PointerEvents>>(mut self, value: impl Res<U>) -> Self {
649 let entity = self.entity();
650 let current = self.current();
651 self.context().with_current(current, |cx| {
652 value.set_or_bind(cx, entity, move |cx, v| {
653 let value = v.get(cx).into();
654 cx.style.pointer_events.insert(cx.current, value);
655 });
656 });
657
658 self
659 }
660
661 fn transform<U: Into<Vec<Transform>>>(mut self, value: impl Res<U>) -> Self {
663 let entity = self.entity();
664 let current = self.current();
665 self.context().with_current(current, |cx| {
666 value.set_or_bind(cx, entity, move |cx, v| {
667 let value = v.get(cx).into();
668 cx.style.transform.insert(cx.current, value);
669 cx.needs_redraw(entity);
670 });
671 });
672
673 self
674 }
675
676 fn transform_origin<U: Into<Position>>(mut self, value: impl Res<U>) -> Self {
678 let entity = self.entity();
679 let current = self.current();
680 self.context().with_current(current, |cx| {
681 value.set_or_bind(cx, entity, move |cx, v| {
682 let value = v.get(cx).into();
683 let x = value.x.to_length_or_percentage();
684 let y = value.y.to_length_or_percentage();
685 cx.style.transform_origin.insert(cx.current, Translate { x, y });
686 cx.needs_redraw(entity);
687 });
688 });
689
690 self
691 }
692
693 modifier!(
695 translate,
699 Translate,
700 SystemFlags::REDRAW
701 );
702
703 modifier!(
705 rotate,
709 Angle,
710 SystemFlags::REDRAW
711 );
712
713 modifier!(
715 scale,
719 Scale,
720 SystemFlags::REDRAW
721 );
722}
723
724impl<V: View> StyleModifiers for Handle<'_, V> {}
725
726#[derive(Debug, Clone)]
728pub struct LinearGradientBuilder {
729 direction: LineDirection,
730 stops: Vec<ColorStop<LengthOrPercentage>>,
731}
732
733impl Default for LinearGradientBuilder {
734 fn default() -> Self {
735 Self::new()
736 }
737}
738
739impl LinearGradientBuilder {
740 pub fn new() -> Self {
742 LinearGradientBuilder { direction: LineDirection::default(), stops: Vec::new() }
743 }
744
745 pub fn with_direction(direction: impl Into<LineDirection>) -> Self {
747 LinearGradientBuilder { direction: direction.into(), stops: Vec::new() }
748 }
749
750 fn build(self) -> Gradient {
751 Gradient::Linear(LinearGradient { direction: self.direction, stops: self.stops })
752 }
753
754 pub fn add_stop(mut self, stop: impl Into<ColorStop<LengthOrPercentage>>) -> Self {
756 self.stops.push(stop.into());
757
758 self
759 }
760}
761
762impl From<LinearGradientBuilder> for Gradient {
763 fn from(value: LinearGradientBuilder) -> Self {
764 value.build()
765 }
766}
767
768#[derive(Debug, Clone)]
770pub struct ShadowBuilder {
771 shadow: Shadow,
772}
773
774impl Default for ShadowBuilder {
775 fn default() -> Self {
776 Self::new()
777 }
778}
779
780impl ShadowBuilder {
781 pub fn new() -> Self {
783 Self { shadow: Shadow::default() }
784 }
785
786 fn build(self) -> Shadow {
787 self.shadow
788 }
789
790 pub fn x_offset(mut self, offset: impl Into<Length>) -> Self {
792 self.shadow.x_offset = offset.into();
793
794 self
795 }
796
797 pub fn y_offset(mut self, offset: impl Into<Length>) -> Self {
799 self.shadow.y_offset = offset.into();
800
801 self
802 }
803
804 pub fn blur(mut self, radius: Length) -> Self {
806 self.shadow.blur_radius = Some(radius);
807
808 self
809 }
810
811 pub fn spread(mut self, radius: Length) -> Self {
813 self.shadow.spread_radius = Some(radius);
814
815 self
816 }
817
818 pub fn color(mut self, color: Color) -> Self {
820 self.shadow.color = Some(color);
821
822 self
823 }
824
825 pub fn inset(mut self) -> Self {
827 self.shadow.inset = true;
828
829 self
830 }
831}
832
833impl From<ShadowBuilder> for Shadow {
834 fn from(value: ShadowBuilder) -> Self {
835 value.build()
836 }
837}