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 _ => None,
418 };
419
420 if let Some(image) = image {
421 cx.style.background_image.insert(cx.current, vec![image]);
422 }
423
424 cx.needs_redraw(entity);
425 });
426 });
427
428 self
429 }
430
431 fn border_width<U: Into<LengthOrPercentage>>(mut self, value: impl Res<U>) -> Self {
433 let entity = self.entity();
434 let current = self.current();
435 value.set_or_bind(self.context(), current, move |cx, v| {
436 cx.style.border_width.insert(entity, v.get(cx).into());
437 cx.cache.path.remove(entity);
438 cx.style.system_flags |= SystemFlags::RELAYOUT | SystemFlags::REDRAW;
439 cx.set_system_flags(entity, SystemFlags::RELAYOUT | SystemFlags::REDRAW);
440 });
441
442 self
443 }
444
445 modifier!(
446 border_color,
448 Color,
449 SystemFlags::REDRAW
450 );
451
452 modifier!(
453 border_style,
455 BorderStyleKeyword,
456 SystemFlags::REDRAW
457 );
458
459 modifier!(
460 corner_top_left_radius,
462 LengthOrPercentage,
463 SystemFlags::REDRAW
464 );
465
466 modifier!(
467 corner_top_right_radius,
469 LengthOrPercentage,
470 SystemFlags::REDRAW
471 );
472
473 modifier!(
474 corner_bottom_left_radius,
476 LengthOrPercentage,
477 SystemFlags::REDRAW
478 );
479
480 modifier!(
481 corner_bottom_right_radius,
483 LengthOrPercentage,
484 SystemFlags::REDRAW
485 );
486
487 fn corner_radius<U: std::fmt::Debug + Into<CornerRadius>>(
489 mut self,
490 value: impl Res<U>,
491 ) -> Self {
492 let entity = self.entity();
493 let current = self.current();
494 self.context().with_current(current, |cx| {
495 value.set_or_bind(cx, entity, move |cx, v| {
496 let value = v.get(cx).into();
497 cx.style.corner_top_left_radius.insert(cx.current, value.top_left);
498 cx.style.corner_top_right_radius.insert(cx.current, value.top_right);
499 cx.style.corner_bottom_left_radius.insert(cx.current, value.bottom_left);
500 cx.style.corner_bottom_right_radius.insert(cx.current, value.bottom_right);
501
502 cx.needs_redraw(entity);
503 });
504 });
505
506 self
507 }
508
509 modifier!(
510 corner_top_left_shape,
512 CornerShape,
513 SystemFlags::REDRAW
514 );
515
516 modifier!(
517 corner_top_right_shape,
519 CornerShape,
520 SystemFlags::REDRAW
521 );
522
523 modifier!(
524 corner_bottom_left_shape,
526 CornerShape,
527 SystemFlags::REDRAW
528 );
529
530 modifier!(
531 corner_bottom_right_shape,
533 CornerShape,
534 SystemFlags::REDRAW
535 );
536
537 fn corner_shape<U: std::fmt::Debug + Into<Rect<CornerShape>>>(
539 mut self,
540 value: impl Res<U>,
541 ) -> Self {
542 let entity = self.entity();
543 let current = self.current();
544 self.context().with_current(current, |cx| {
545 value.set_or_bind(cx, entity, move |cx, v| {
546 let value = v.get(cx).into();
547 cx.style.corner_top_left_shape.insert(cx.current, value.0);
548 cx.style.corner_top_right_shape.insert(cx.current, value.1);
549 cx.style.corner_bottom_right_shape.insert(cx.current, value.2);
550 cx.style.corner_bottom_left_shape.insert(cx.current, value.3);
551
552 cx.needs_redraw(entity);
553 });
554 });
555
556 self
557 }
558
559 modifier!(
560 corner_top_left_smoothing,
562 f32,
563 SystemFlags::REDRAW
564 );
565
566 modifier!(
567 corner_top_right_smoothing,
569 f32,
570 SystemFlags::REDRAW
571 );
572
573 modifier!(
574 corner_bottom_left_smoothing,
576 f32,
577 SystemFlags::REDRAW
578 );
579
580 modifier!(
581 corner_bottom_right_smoothing,
583 f32,
584 SystemFlags::REDRAW
585 );
586
587 fn corner_smoothing<U: std::fmt::Debug + Into<Rect<f32>>>(
589 mut self,
590 value: impl Res<U>,
591 ) -> Self {
592 let entity = self.entity();
593 let current = self.current();
594 self.context().with_current(current, |cx| {
595 value.set_or_bind(cx, entity, move |cx, v| {
596 let value = v.get(cx).into();
597 cx.style.corner_top_left_smoothing.insert(cx.current, value.0);
598 cx.style.corner_top_right_smoothing.insert(cx.current, value.1);
599 cx.style.corner_bottom_left_smoothing.insert(cx.current, value.2);
600 cx.style.corner_bottom_right_smoothing.insert(cx.current, value.3);
601
602 cx.needs_redraw(entity);
603 });
604 });
605
606 self
607 }
608
609 modifier!(
611 outline_width,
613 LengthOrPercentage,
614 SystemFlags::REDRAW
615 );
616
617 modifier!(
618 outline_color,
620 Color,
621 SystemFlags::REDRAW
622 );
623
624 modifier!(
625 outline_offset,
627 LengthOrPercentage,
628 SystemFlags::REDRAW
629 );
630
631 modifier!(
632 fill,
634 Color,
635 SystemFlags::REDRAW
636 );
637
638 modifier!(
640 cursor,
642 CursorIcon,
643 SystemFlags::empty()
644 );
645
646 fn pointer_events<U: Into<PointerEvents>>(mut self, value: impl Res<U>) -> Self {
648 let entity = self.entity();
649 let current = self.current();
650 self.context().with_current(current, |cx| {
651 value.set_or_bind(cx, entity, move |cx, v| {
652 let value = v.get(cx).into();
653 cx.style.pointer_events.insert(cx.current, value);
654 });
655 });
656
657 self
658 }
659
660 fn transform<U: Into<Vec<Transform>>>(mut self, value: impl Res<U>) -> Self {
662 let entity = self.entity();
663 let current = self.current();
664 self.context().with_current(current, |cx| {
665 value.set_or_bind(cx, entity, move |cx, v| {
666 let value = v.get(cx).into();
667 cx.style.transform.insert(cx.current, value);
668 cx.needs_redraw(entity);
669 });
670 });
671
672 self
673 }
674
675 fn transform_origin<U: Into<Position>>(mut self, value: impl Res<U>) -> Self {
677 let entity = self.entity();
678 let current = self.current();
679 self.context().with_current(current, |cx| {
680 value.set_or_bind(cx, entity, move |cx, v| {
681 let value = v.get(cx).into();
682 let x = value.x.to_length_or_percentage();
683 let y = value.y.to_length_or_percentage();
684 cx.style.transform_origin.insert(cx.current, Translate { x, y });
685 cx.needs_redraw(entity);
686 });
687 });
688
689 self
690 }
691
692 modifier!(
694 translate,
698 Translate,
699 SystemFlags::REDRAW
700 );
701
702 modifier!(
704 rotate,
708 Angle,
709 SystemFlags::REDRAW
710 );
711
712 modifier!(
714 scale,
718 Scale,
719 SystemFlags::REDRAW
720 );
721}
722
723impl<V: View> StyleModifiers for Handle<'_, V> {}
724
725#[derive(Debug, Clone)]
727pub struct LinearGradientBuilder {
728 direction: LineDirection,
729 stops: Vec<ColorStop<LengthOrPercentage>>,
730}
731
732impl Default for LinearGradientBuilder {
733 fn default() -> Self {
734 Self::new()
735 }
736}
737
738impl LinearGradientBuilder {
739 pub fn new() -> Self {
741 LinearGradientBuilder { direction: LineDirection::default(), stops: Vec::new() }
742 }
743
744 pub fn with_direction(direction: impl Into<LineDirection>) -> Self {
746 LinearGradientBuilder { direction: direction.into(), stops: Vec::new() }
747 }
748
749 fn build(self) -> Gradient {
750 Gradient::Linear(LinearGradient { direction: self.direction, stops: self.stops })
751 }
752
753 pub fn add_stop(mut self, stop: impl Into<ColorStop<LengthOrPercentage>>) -> Self {
755 self.stops.push(stop.into());
756
757 self
758 }
759}
760
761impl From<LinearGradientBuilder> for Gradient {
762 fn from(value: LinearGradientBuilder) -> Self {
763 value.build()
764 }
765}
766
767#[derive(Debug, Clone)]
769pub struct ShadowBuilder {
770 shadow: Shadow,
771}
772
773impl Default for ShadowBuilder {
774 fn default() -> Self {
775 Self::new()
776 }
777}
778
779impl ShadowBuilder {
780 pub fn new() -> Self {
782 Self { shadow: Shadow::default() }
783 }
784
785 fn build(self) -> Shadow {
786 self.shadow
787 }
788
789 pub fn x_offset(mut self, offset: impl Into<Length>) -> Self {
791 self.shadow.x_offset = offset.into();
792
793 self
794 }
795
796 pub fn y_offset(mut self, offset: impl Into<Length>) -> Self {
798 self.shadow.y_offset = offset.into();
799
800 self
801 }
802
803 pub fn blur(mut self, radius: Length) -> Self {
805 self.shadow.blur_radius = Some(radius);
806
807 self
808 }
809
810 pub fn spread(mut self, radius: Length) -> Self {
812 self.shadow.spread_radius = Some(radius);
813
814 self
815 }
816
817 pub fn color(mut self, color: Color) -> Self {
819 self.shadow.color = Some(color);
820
821 self
822 }
823
824 pub fn inset(mut self) -> Self {
826 self.shadow.inset = true;
827
828 self
829 }
830}
831
832impl From<ShadowBuilder> for Shadow {
833 fn from(value: ShadowBuilder) -> Self {
834 value.build()
835 }
836}