1use std::{
2 borrow::Cow,
3 hash::{
4 Hash,
5 Hasher,
6 },
7};
8
9use paste::paste;
10use ragnarok::CursorPoint;
11use rustc_hash::{
12 FxHashMap,
13 FxHasher,
14};
15use torin::{
16 content::Content,
17 gaps::Gaps,
18 prelude::{
19 Alignment,
20 Direction,
21 Length,
22 Position,
23 VisibleSize,
24 },
25 size::Size,
26};
27
28use crate::{
29 data::{
30 AccessibilityData,
31 EffectData,
32 LayoutData,
33 Overflow,
34 TextStyleData,
35 },
36 diff_key::DiffKey,
37 element::{
38 Element,
39 EventHandlerType,
40 },
41 elements::image::{
42 AspectRatio,
43 ImageCover,
44 ImageData,
45 SamplingMode,
46 },
47 event_handler::EventHandler,
48 events::{
49 data::{
50 Event,
51 KeyboardEventData,
52 MouseEventData,
53 SizedEventData,
54 WheelEventData,
55 },
56 name::EventName,
57 },
58 layers::Layer,
59 prelude::*,
60 style::{
61 font_size::FontSize,
62 font_slant::FontSlant,
63 font_weight::FontWeight,
64 font_width::FontWidth,
65 scale::Scale,
66 shader::ShaderFill,
67 text_height::TextHeightBehavior,
68 text_overflow::TextOverflow,
69 text_shadow::TextShadow,
70 },
71};
72
73pub trait ChildrenExt: Sized {
75 fn get_children(&mut self) -> &mut Vec<Element>;
86
87 fn children(mut self, children: impl IntoIterator<Item = Element>) -> Self {
94 self.get_children().extend(children);
95 self
96 }
97
98 fn maybe_child<C: IntoElement>(mut self, child: Option<C>) -> Self {
105 if let Some(child) = child {
106 self.get_children().push(child.into_element());
107 }
108 self
109 }
110
111 fn child<C: IntoElement>(mut self, child: C) -> Self {
118 self.get_children().push(child.into_element());
119 self
120 }
121}
122
123pub trait KeyExt: Sized {
124 fn write_key(&mut self) -> &mut DiffKey;
125
126 fn key(mut self, key: impl Hash) -> Self {
127 let mut hasher = FxHasher::default();
128 key.hash(&mut hasher);
129 *self.write_key() = DiffKey::U64(hasher.finish());
130 self
131 }
132}
133
134pub trait ListExt {
135 fn with(self, other: Self) -> Self;
136}
137
138impl<T> ListExt for Vec<T> {
139 fn with(mut self, other: Self) -> Self {
140 self.extend(other);
141 self
142 }
143}
144
145macro_rules! event_handlers {
146 (
147 $handler_variant:ident, $event_data:ty;
148 $(
149 $name:ident => $event_variant:expr ;
150 )*
151 ) => {
152 paste! {
153 $(
154 fn [<on_$name>](mut self, [<on_$name>]: impl Into<EventHandler<Event<$event_data>>>) -> Self {
155 self.get_event_handlers()
156 .insert($event_variant, EventHandlerType::$handler_variant([<on_$name>].into()));
157 self
158 }
159 )*
160 }
161 };
162}
163
164pub trait EventHandlersExt: Sized {
165 fn get_event_handlers(&mut self) -> &mut FxHashMap<EventName, EventHandlerType>;
166
167 fn with_event_handlers(
168 mut self,
169 event_handlers: FxHashMap<EventName, EventHandlerType>,
170 ) -> Self {
171 *self.get_event_handlers() = event_handlers;
172 self
173 }
174
175 event_handlers! {
176 Mouse,
177 MouseEventData;
178
179 mouse_down => EventName::MouseDown;
180 mouse_up => EventName::MouseUp;
181 mouse_move => EventName::MouseMove;
182
183 }
184
185 event_handlers! {
186 Pointer,
187 PointerEventData;
188
189 global_pointer_press => EventName::GlobalPointerPress;
190 global_pointer_down => EventName::GlobalPointerDown;
191 global_pointer_move => EventName::GlobalPointerMove;
192
193 capture_global_pointer_move => EventName::CaptureGlobalPointerMove;
194 capture_global_pointer_press => EventName::CaptureGlobalPointerPress;
195 }
196
197 event_handlers! {
198 Keyboard,
199 KeyboardEventData;
200
201 key_down => EventName::KeyDown;
202 key_up => EventName::KeyUp;
203
204 global_key_down => EventName::GlobalKeyDown;
205 global_key_up => EventName::GlobalKeyUp;
206 }
207
208 event_handlers! {
209 Wheel,
210 WheelEventData;
211
212 wheel => EventName::Wheel;
213 }
214
215 event_handlers! {
216 Touch,
217 TouchEventData;
218
219 touch_cancel => EventName::TouchCancel;
220 touch_start => EventName::TouchStart;
221 touch_move => EventName::TouchMove;
222 touch_end => EventName::TouchEnd;
223 }
224
225 event_handlers! {
226 Pointer,
227 PointerEventData;
228
229 pointer_press => EventName::PointerPress;
230 pointer_down => EventName::PointerDown;
231 pointer_move => EventName::PointerMove;
232 pointer_enter => EventName::PointerEnter;
233 pointer_leave => EventName::PointerLeave;
234 pointer_over => EventName::PointerOver;
235 pointer_out => EventName::PointerOut;
236 }
237
238 event_handlers! {
239 File,
240 FileEventData;
241
242 file_drop => EventName::FileDrop;
243 global_file_hover => EventName::GlobalFileHover;
244 global_file_hover_cancelled => EventName::GlobalFileHoverCancelled;
245 }
246
247 event_handlers! {
248 ImePreedit,
249 ImePreeditEventData;
250
251 ime_preedit => EventName::ImePreedit;
252 }
253
254 fn on_sized(mut self, on_sized: impl Into<EventHandler<Event<SizedEventData>>>) -> Self
255 where
256 Self: LayoutExt,
257 {
258 self.get_event_handlers()
259 .insert(EventName::Sized, EventHandlerType::Sized(on_sized.into()));
260 self.get_layout().layout.has_layout_references = true;
261 self
262 }
263
264 fn on_press(self, on_press: impl Into<EventHandler<Event<PressEventData>>>) -> Self {
271 let on_press = on_press.into();
272 self.on_pointer_press({
273 let on_press = on_press.clone();
274 move |e: Event<PointerEventData>| {
275 let event = e.try_map(|d| match d {
276 PointerEventData::Mouse(m) if m.button == Some(MouseButton::Left) => {
277 Some(PressEventData::Mouse(m))
278 }
279 PointerEventData::Touch(t) => Some(PressEventData::Touch(t)),
280 _ => None,
281 });
282 if let Some(event) = event {
283 on_press.call(event);
284 }
285 }
286 })
287 .on_key_down(move |e: Event<KeyboardEventData>| {
288 if e.is_press_event() {
289 on_press.call(e.map(PressEventData::Keyboard))
290 }
291 })
292 }
293
294 fn on_secondary_down(
298 self,
299 on_secondary_down: impl Into<EventHandler<Event<PressEventData>>>,
300 ) -> Self {
301 let on_secondary_down = on_secondary_down.into();
302 self.on_pointer_down(move |e: Event<PointerEventData>| {
303 let event = e.try_map(|d| match d {
304 PointerEventData::Mouse(m) if m.button == Some(MouseButton::Right) => {
305 Some(PressEventData::Mouse(m))
306 }
307 _ => None,
308 });
309 if let Some(event) = event {
310 on_secondary_down.call(event);
311 }
312 })
313 }
314
315 fn on_all_press(self, on_press: impl Into<EventHandler<Event<PressEventData>>>) -> Self {
320 let on_press = on_press.into();
321 self.on_pointer_press({
322 let on_press = on_press.clone();
323 move |e: Event<PointerEventData>| {
324 let event = e.map(|d| match d {
325 PointerEventData::Mouse(m) => PressEventData::Mouse(m),
326 PointerEventData::Touch(t) => PressEventData::Touch(t),
327 });
328 on_press.call(event);
329 }
330 })
331 .on_key_down(move |e: Event<KeyboardEventData>| {
332 if e.is_press_event() {
333 on_press.call(e.map(PressEventData::Keyboard))
334 }
335 })
336 }
337 fn on_focus_press(
343 self,
344 on_focus_press: impl Into<EventHandler<Event<FocusPressEventData>>>,
345 ) -> Self {
346 let on_focus_press = on_focus_press.into();
347 if cfg!(target_os = "android") {
348 self.on_pointer_press(move |e: Event<PointerEventData>| {
349 let event = e.try_map(|d| match d {
350 PointerEventData::Mouse(m) if m.button == Some(MouseButton::Left) => {
351 Some(FocusPressEventData::Mouse(m))
352 }
353 PointerEventData::Touch(t) => Some(FocusPressEventData::Touch(t)),
354 _ => None,
355 });
356 if let Some(event) = event {
357 on_focus_press.call(event);
358 }
359 })
360 } else {
361 self.on_pointer_down(move |e: Event<PointerEventData>| {
362 let event = e.try_map(|d| match d {
363 PointerEventData::Mouse(m) if m.button == Some(MouseButton::Left) => {
364 Some(FocusPressEventData::Mouse(m))
365 }
366 PointerEventData::Touch(t) => Some(FocusPressEventData::Touch(t)),
367 _ => None,
368 });
369 if let Some(event) = event {
370 on_focus_press.call(event);
371 }
372 })
373 }
374 }
375}
376
377#[derive(Debug, Clone, PartialEq)]
378pub enum FocusPressEventData {
379 Mouse(MouseEventData),
380 Touch(TouchEventData),
381}
382
383impl FocusPressEventData {
384 pub fn global_location(&self) -> CursorPoint {
385 match self {
386 Self::Mouse(m) => m.global_location,
387 Self::Touch(t) => t.global_location,
388 }
389 }
390
391 pub fn element_location(&self) -> CursorPoint {
392 match self {
393 Self::Mouse(m) => m.element_location,
394 Self::Touch(t) => t.element_location,
395 }
396 }
397
398 pub fn button(&self) -> Option<MouseButton> {
399 match self {
400 Self::Mouse(m) => m.button,
401 Self::Touch(_) => None,
402 }
403 }
404}
405
406#[derive(Debug, Clone, PartialEq)]
407pub enum PressEventData {
408 Mouse(MouseEventData),
409 Keyboard(KeyboardEventData),
410 Touch(TouchEventData),
411}
412
413pub trait ContainerWithContentExt
414where
415 Self: LayoutExt,
416{
417 fn direction(mut self, direction: Direction) -> Self {
418 self.get_layout().layout.direction = direction;
419 self
420 }
421 fn main_align(mut self, main_align: Alignment) -> Self {
422 self.get_layout().layout.main_alignment = main_align;
423 self
424 }
425
426 fn cross_align(mut self, cross_align: Alignment) -> Self {
427 self.get_layout().layout.cross_alignment = cross_align;
428 self
429 }
430
431 fn spacing(mut self, spacing: impl Into<f32>) -> Self {
432 self.get_layout().layout.spacing = Length::new(spacing.into());
433 self
434 }
435
436 fn content(mut self, content: Content) -> Self {
437 self.get_layout().layout.content = content;
438 self
439 }
440 fn center(mut self) -> Self {
441 self.get_layout().layout.main_alignment = Alignment::Center;
442 self.get_layout().layout.cross_alignment = Alignment::Center;
443
444 self
445 }
446
447 fn offset_x(mut self, offset_x: impl Into<f32>) -> Self {
448 self.get_layout().layout.offset_x = Length::new(offset_x.into());
449 self
450 }
451
452 fn offset_y(mut self, offset_y: impl Into<f32>) -> Self {
453 self.get_layout().layout.offset_y = Length::new(offset_y.into());
454 self
455 }
456
457 fn vertical(mut self) -> Self {
458 self.get_layout().layout.direction = Direction::vertical();
459 self
460 }
461
462 fn horizontal(mut self) -> Self {
463 self.get_layout().layout.direction = Direction::horizontal();
464 self
465 }
466}
467
468pub trait ContainerSizeExt
469where
470 Self: LayoutExt,
471{
472 fn width(mut self, width: impl Into<Size>) -> Self {
473 self.get_layout().layout.width = width.into();
474 self
475 }
476
477 fn height(mut self, height: impl Into<Size>) -> Self {
478 self.get_layout().layout.height = height.into();
479 self
480 }
481
482 fn expanded(mut self) -> Self {
484 self.get_layout().layout.width = Size::fill();
485 self.get_layout().layout.height = Size::fill();
486 self
487 }
488}
489
490impl<T: ContainerExt> ContainerSizeExt for T {}
491
492pub trait ContainerExt
493where
494 Self: LayoutExt,
495{
496 fn position(mut self, position: impl Into<Position>) -> Self {
497 self.get_layout().layout.position = position.into();
498 self
499 }
500
501 fn padding(mut self, padding: impl Into<Gaps>) -> Self {
502 self.get_layout().layout.padding = padding.into();
503 self
504 }
505
506 fn margin(mut self, margin: impl Into<Gaps>) -> Self {
507 self.get_layout().layout.margin = margin.into();
508 self
509 }
510
511 fn min_width(mut self, minimum_width: impl Into<Size>) -> Self {
512 self.get_layout().layout.minimum_width = minimum_width.into();
513 self
514 }
515
516 fn min_height(mut self, minimum_height: impl Into<Size>) -> Self {
517 self.get_layout().layout.minimum_height = minimum_height.into();
518 self
519 }
520
521 fn max_width(mut self, maximum_width: impl Into<Size>) -> Self {
522 self.get_layout().layout.maximum_width = maximum_width.into();
523 self
524 }
525
526 fn max_height(mut self, maximum_height: impl Into<Size>) -> Self {
527 self.get_layout().layout.maximum_height = maximum_height.into();
528 self
529 }
530
531 fn visible_width(mut self, visible_width: impl Into<VisibleSize>) -> Self {
532 self.get_layout().layout.visible_width = visible_width.into();
533 self
534 }
535
536 fn visible_height(mut self, visible_height: impl Into<VisibleSize>) -> Self {
537 self.get_layout().layout.visible_height = visible_height.into();
538 self
539 }
540}
541
542pub trait LayoutExt
543where
544 Self: Sized,
545{
546 fn get_layout(&mut self) -> &mut LayoutData;
547
548 fn layout(mut self, layout: LayoutData) -> Self {
549 *self.get_layout() = layout;
550 self
551 }
552}
553
554pub trait ImageExt
555where
556 Self: LayoutExt,
557{
558 fn get_image_data(&mut self) -> &mut ImageData;
559
560 fn image_data(mut self, image_data: ImageData) -> Self {
561 *self.get_image_data() = image_data;
562 self
563 }
564
565 fn sampling_mode(mut self, sampling_mode: SamplingMode) -> Self {
566 self.get_image_data().sampling_mode = sampling_mode;
567 self
568 }
569
570 fn aspect_ratio(mut self, aspect_ratio: AspectRatio) -> Self {
571 self.get_image_data().aspect_ratio = aspect_ratio;
572 self
573 }
574
575 fn image_cover(mut self, image_cover: ImageCover) -> Self {
576 self.get_image_data().image_cover = image_cover;
577 self
578 }
579}
580
581pub trait AccessibilityExt: Sized {
582 fn get_accessibility_data(&mut self) -> &mut AccessibilityData;
583
584 fn accessibility(mut self, accessibility: AccessibilityData) -> Self {
585 *self.get_accessibility_data() = accessibility;
586 self
587 }
588
589 fn a11y_id(mut self, a11y_id: impl Into<Option<AccessibilityId>>) -> Self {
590 self.get_accessibility_data().a11y_id = a11y_id.into();
591 self
592 }
593
594 fn a11y_focusable(mut self, a11y_focusable: impl Into<Focusable>) -> Self {
595 self.get_accessibility_data().a11y_focusable = a11y_focusable.into();
596 self
597 }
598
599 fn a11y_auto_focus(mut self, a11y_auto_focus: impl Into<bool>) -> Self {
600 self.get_accessibility_data().a11y_auto_focus = a11y_auto_focus.into();
601 self
602 }
603
604 fn a11y_member_of(mut self, a11y_member_of: impl Into<AccessibilityId>) -> Self {
605 self.get_accessibility_data()
606 .builder
607 .set_member_of(a11y_member_of.into());
608 self
609 }
610
611 fn a11y_role(mut self, a11y_role: impl Into<AccessibilityRole>) -> Self {
612 self.get_accessibility_data()
613 .builder
614 .set_role(a11y_role.into());
615 self
616 }
617
618 fn a11y_alt(mut self, value: impl Into<Box<str>>) -> Self {
619 self.get_accessibility_data().builder.set_label(value);
620 self
621 }
622
623 fn a11y_builder(mut self, with: impl FnOnce(&mut accesskit::Node)) -> Self {
624 with(&mut self.get_accessibility_data().builder);
625 self
626 }
627}
628
629pub trait TextStyleExt
630where
631 Self: Sized,
632{
633 fn get_text_style_data(&mut self) -> &mut TextStyleData;
634
635 fn text_style(mut self, data: TextStyleData) -> Self {
636 *self.get_text_style_data() = data;
637 self
638 }
639
640 fn color(mut self, color: impl Into<Color>) -> Self {
641 self.get_text_style_data().color = Some(Fill::Color(color.into()));
642 self
643 }
644
645 fn color_conic_gradient<S: Into<ConicGradient>>(mut self, color: S) -> Self {
646 self.get_text_style_data().color = Some(Fill::ConicGradient(Box::new(color.into())));
647 self
648 }
649
650 fn color_linear_gradient<S: Into<LinearGradient>>(mut self, color: S) -> Self {
651 self.get_text_style_data().color = Some(Fill::LinearGradient(Box::new(color.into())));
652 self
653 }
654
655 fn color_radial_gradient<S: Into<RadialGradient>>(mut self, color: S) -> Self {
656 self.get_text_style_data().color = Some(Fill::RadialGradient(Box::new(color.into())));
657 self
658 }
659
660 fn color_shader(mut self, color: impl Into<ShaderFill>) -> Self {
661 self.get_text_style_data().color = Some(Fill::Shader(Box::new(color.into())));
662 self
663 }
664
665 fn text_align(mut self, text_align: impl Into<TextAlign>) -> Self {
666 self.get_text_style_data().text_align = Some(text_align.into());
667 self
668 }
669
670 fn font_size(mut self, font_size: impl Into<FontSize>) -> Self {
671 self.get_text_style_data().font_size = Some(font_size.into());
672 self
673 }
674
675 fn font_family(mut self, font_family: impl Into<Cow<'static, str>>) -> Self {
676 self.get_text_style_data()
677 .font_families
678 .push(font_family.into());
679 self
680 }
681
682 fn font_slant(mut self, font_slant: impl Into<FontSlant>) -> Self {
683 self.get_text_style_data().font_slant = Some(font_slant.into());
684 self
685 }
686
687 fn font_weight(mut self, font_weight: impl Into<FontWeight>) -> Self {
688 self.get_text_style_data().font_weight = Some(font_weight.into());
689 self
690 }
691
692 fn font_width(mut self, font_width: impl Into<FontWidth>) -> Self {
693 self.get_text_style_data().font_width = Some(font_width.into());
694 self
695 }
696
697 fn text_height(mut self, text_height: impl Into<TextHeightBehavior>) -> Self {
698 self.get_text_style_data().text_height = Some(text_height.into());
699 self
700 }
701
702 fn text_overflow(mut self, text_overflow: impl Into<TextOverflow>) -> Self {
703 self.get_text_style_data().text_overflow = Some(text_overflow.into());
704 self
705 }
706
707 fn text_shadow(mut self, text_shadow: impl Into<TextShadow>) -> Self {
708 self.get_text_style_data()
709 .text_shadows
710 .push(text_shadow.into());
711 self
712 }
713
714 fn text_decoration(mut self, text_decoration: impl Into<TextDecoration>) -> Self {
715 self.get_text_style_data().text_decoration = Some(text_decoration.into());
716 self
717 }
718}
719
720pub trait StyleExt
721where
722 Self: Sized,
723{
724 fn get_style(&mut self) -> &mut StyleState;
725
726 fn background<S: Into<Color>>(mut self, background: S) -> Self {
727 self.get_style().background = Fill::Color(background.into());
728 self
729 }
730
731 fn background_conic_gradient<S: Into<ConicGradient>>(mut self, background: S) -> Self {
732 self.get_style().background = Fill::ConicGradient(Box::new(background.into()));
733 self
734 }
735
736 fn background_linear_gradient<S: Into<LinearGradient>>(mut self, background: S) -> Self {
737 self.get_style().background = Fill::LinearGradient(Box::new(background.into()));
738 self
739 }
740
741 fn background_radial_gradient<S: Into<RadialGradient>>(mut self, background: S) -> Self {
742 self.get_style().background = Fill::RadialGradient(Box::new(background.into()));
743 self
744 }
745
746 fn background_shader(mut self, background: impl Into<ShaderFill>) -> Self {
747 self.get_style().background = Fill::Shader(Box::new(background.into()));
748 self
749 }
750
751 fn border(mut self, border: impl Into<Option<Border>>) -> Self {
752 if let Some(border) = border.into() {
753 self.get_style().borders.push(border);
754 }
755 self
756 }
757
758 fn shadow(mut self, shadow: impl Into<Shadow>) -> Self {
759 self.get_style().shadows.push(shadow.into());
760 self
761 }
762
763 fn corner_radius(mut self, corner_radius: impl Into<CornerRadius>) -> Self {
764 self.get_style().corner_radius = corner_radius.into();
765 self
766 }
767}
768
769impl<T: StyleExt> CornerRadiusExt for T {
770 fn with_corner_radius(mut self, corner_radius: f32) -> Self {
771 self.get_style().corner_radius = CornerRadius::new_all(corner_radius);
772 self
773 }
774}
775
776pub trait CornerRadiusExt: Sized {
777 fn with_corner_radius(self, corner_radius: f32) -> Self;
778
779 fn rounded_none(self) -> Self {
781 self.with_corner_radius(0.)
782 }
783
784 fn rounded(self) -> Self {
786 self.with_corner_radius(6.)
787 }
788
789 fn rounded_sm(self) -> Self {
791 self.with_corner_radius(4.)
792 }
793
794 fn rounded_md(self) -> Self {
796 self.with_corner_radius(6.)
797 }
798
799 fn rounded_lg(self) -> Self {
801 self.with_corner_radius(8.)
802 }
803
804 fn rounded_xl(self) -> Self {
806 self.with_corner_radius(12.)
807 }
808
809 fn rounded_2xl(self) -> Self {
811 self.with_corner_radius(16.)
812 }
813
814 fn rounded_3xl(self) -> Self {
816 self.with_corner_radius(24.)
817 }
818
819 fn rounded_4xl(self) -> Self {
821 self.with_corner_radius(32.)
822 }
823
824 fn rounded_full(self) -> Self {
826 self.with_corner_radius(99.)
827 }
828}
829
830pub trait MaybeExt
831where
832 Self: Sized,
833{
834 fn maybe(self, bool: impl Into<bool>, then: impl FnOnce(Self) -> Self) -> Self {
835 if bool.into() { then(self) } else { self }
836 }
837
838 fn map<T>(self, data: Option<T>, then: impl FnOnce(Self, T) -> Self) -> Self {
839 if let Some(data) = data {
840 then(self, data)
841 } else {
842 self
843 }
844 }
845}
846
847pub trait LayerExt
848where
849 Self: Sized,
850{
851 fn get_layer(&mut self) -> &mut Layer;
852
853 fn layer(mut self, layer: impl Into<Layer>) -> Self {
854 *self.get_layer() = layer.into();
855 self
856 }
857}
858
859pub trait ScrollableExt
860where
861 Self: Sized,
862{
863 fn get_effect(&mut self) -> &mut EffectData;
864
865 fn scrollable(mut self, scrollable: impl Into<bool>) -> Self {
868 self.get_effect().scrollable = scrollable.into();
869 self
870 }
871}
872
873pub trait InteractiveExt
874where
875 Self: Sized,
876{
877 fn get_effect(&mut self) -> &mut EffectData;
878
879 fn interactive(mut self, interactive: impl Into<Interactive>) -> Self {
880 self.get_effect().interactive = interactive.into();
881 self
882 }
883}
884
885pub trait EffectExt: Sized {
886 fn get_effect(&mut self) -> &mut EffectData;
887
888 fn effect(mut self, effect: EffectData) -> Self {
889 *self.get_effect() = effect;
890 self
891 }
892
893 fn overflow(mut self, overflow: impl Into<Overflow>) -> Self {
894 self.get_effect().overflow = overflow.into();
895 self
896 }
897
898 fn blur(mut self, blur: impl Into<f32>) -> Self {
899 self.get_effect().blur = Some(blur.into());
900 self
901 }
902
903 fn rotation(mut self, rotation: impl Into<f32>) -> Self {
904 self.get_effect().rotation = Some(rotation.into());
905 self
906 }
907
908 fn opacity(mut self, opacity: impl Into<f32>) -> Self {
909 self.get_effect().opacity = Some(opacity.into());
910 self
911 }
912
913 fn scale(mut self, scale: impl Into<Scale>) -> Self {
914 self.get_effect().scale = Some(scale.into());
915 self
916 }
917}