1use std::{
2 borrow::Cow,
3 hash::{
4 Hash,
5 Hasher,
6 },
7};
8
9use paste::paste;
10use ragnarok::CursorPoint;
11use rustc_hash::FxHasher;
12use torin::{
13 content::Content,
14 gaps::Gaps,
15 prelude::{
16 Alignment,
17 Direction,
18 Length,
19 Position,
20 VisibleSize,
21 },
22 size::Size,
23};
24
25use crate::{
26 data::{
27 AccessibilityData,
28 EffectData,
29 LayoutData,
30 Overflow,
31 TextStyleData,
32 },
33 diff_key::DiffKey,
34 element::{
35 Element,
36 EventHandlerType,
37 EventHandlers,
38 },
39 elements::image::{
40 AspectRatio,
41 ImageCover,
42 ImageData,
43 SamplingMode,
44 },
45 event_handler::EventHandler,
46 events::{
47 data::{
48 Event,
49 KeyboardEventData,
50 MouseEventData,
51 SizedEventData,
52 StyledEventData,
53 WheelEventData,
54 },
55 name::EventName,
56 },
57 layers::Layer,
58 prelude::*,
59 style::{
60 font_size::FontSize,
61 font_slant::FontSlant,
62 font_weight::FontWeight,
63 font_width::FontWidth,
64 scale::Scale,
65 text_height::TextHeightBehavior,
66 text_overflow::TextOverflow,
67 text_shadow::TextShadow,
68 transform_origin::TransformOrigin,
69 },
70};
71
72pub trait ChildrenExt: Sized {
74 fn get_children(&mut self) -> &mut Vec<Element>;
85
86 fn children(mut self, children: impl IntoIterator<Item = impl IntoElement>) -> Self {
93 self.get_children()
94 .extend(children.into_iter().map(IntoElement::into_element));
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 {
125 fn write_key(&mut self) -> &mut DiffKey;
127
128 fn key(mut self, key: impl Hash) -> Self
132 where
133 Self: 'static,
134 {
135 let mut hasher = FxHasher::default();
136 std::any::TypeId::of::<Self>().hash(&mut hasher);
137 key.hash(&mut hasher);
138 *self.write_key() = DiffKey::U64(hasher.finish());
139 self
140 }
141}
142
143pub trait ListExt {
145 fn with(self, other: Self) -> Self;
147}
148
149impl<T> ListExt for Vec<T> {
150 fn with(mut self, other: Self) -> Self {
151 self.extend(other);
152 self
153 }
154}
155
156macro_rules! event_handlers {
157 (
158 $handler_variant:ident, $event_data:ty;
159 $(
160 $(#[$attr:meta])*
161 $name:ident => $event_variant:expr ;
162 )*
163 ) => {
164 paste! {
165 $(
166 $(#[$attr])*
167 fn [<on_$name>](mut self, [<on_$name>]: impl Into<EventHandler<Event<$event_data>>>) -> Self {
168 self.get_event_handlers()
169 .insert($event_variant, EventHandlerType::$handler_variant([<on_$name>].into()));
170 self
171 }
172 )*
173 }
174 };
175}
176
177pub trait EventHandlersExt: Sized {
185 fn get_event_handlers(&mut self) -> &mut EventHandlers;
187
188 fn event_handlers(mut self, event_handlers: EventHandlers) -> Self {
190 *self.get_event_handlers() = event_handlers;
191 self
192 }
193
194 event_handlers! {
195 Mouse,
196 MouseEventData;
197
198 mouse_down => EventName::MouseDown;
200 mouse_up => EventName::MouseUp;
202 mouse_move => EventName::MouseMove;
204
205 }
206
207 event_handlers! {
208 Pointer,
209 PointerEventData;
210
211 global_pointer_press => EventName::GlobalPointerPress;
213 global_pointer_down => EventName::GlobalPointerDown;
215 global_pointer_move => EventName::GlobalPointerMove;
217
218 capture_global_pointer_move => EventName::CaptureGlobalPointerMove;
220 capture_global_pointer_press => EventName::CaptureGlobalPointerPress;
222 }
223
224 event_handlers! {
225 Keyboard,
226 KeyboardEventData;
227
228 key_down => EventName::KeyDown;
230 key_up => EventName::KeyUp;
232
233 global_key_down => EventName::GlobalKeyDown;
235 global_key_up => EventName::GlobalKeyUp;
237 }
238
239 event_handlers! {
240 Wheel,
241 WheelEventData;
242
243 wheel => EventName::Wheel;
245 }
246
247 event_handlers! {
248 Touch,
249 TouchEventData;
250
251 touch_cancel => EventName::TouchCancel;
253 touch_start => EventName::TouchStart;
255 touch_move => EventName::TouchMove;
257 touch_end => EventName::TouchEnd;
259 }
260
261 event_handlers! {
262 Pointer,
263 PointerEventData;
264
265 pointer_press => EventName::PointerPress;
267 pointer_down => EventName::PointerDown;
269 pointer_move => EventName::PointerMove;
271 pointer_enter => EventName::PointerEnter;
273 pointer_leave => EventName::PointerLeave;
275 pointer_over => EventName::PointerOver;
277 pointer_out => EventName::PointerOut;
279 }
280
281 event_handlers! {
282 File,
283 FileEventData;
284
285 file_drop => EventName::FileDrop;
287 global_file_hover => EventName::GlobalFileHover;
289 global_file_hover_cancelled => EventName::GlobalFileHoverCancelled;
291 }
292
293 event_handlers! {
294 ImePreedit,
295 ImePreeditEventData;
296
297 ime_preedit => EventName::ImePreedit;
299 }
300
301 fn on_sized(mut self, on_sized: impl Into<EventHandler<Event<SizedEventData>>>) -> Self
303 where
304 Self: LayoutExt,
305 {
306 self.get_event_handlers()
307 .insert(EventName::Sized, EventHandlerType::Sized(on_sized.into()));
308 self.get_layout().layout.has_layout_references = true;
309 self
310 }
311
312 fn on_styled(mut self, on_styled: impl Into<EventHandler<Event<StyledEventData>>>) -> Self {
314 self.get_event_handlers().insert(
315 EventName::Styled,
316 EventHandlerType::Styled(on_styled.into()),
317 );
318 self
319 }
320
321 fn on_press(self, on_press: impl Into<EventHandler<Event<PressEventData>>>) -> Self {
328 let on_press = on_press.into();
329 self.on_pointer_press({
330 let on_press = on_press.clone();
331 move |e: Event<PointerEventData>| {
332 let event = e.try_map(|d| match d {
333 PointerEventData::Mouse(m) if m.button == Some(MouseButton::Left) => {
334 Some(PressEventData::Mouse(m))
335 }
336 PointerEventData::Touch(t) => Some(PressEventData::Touch(t)),
337 _ => None,
338 });
339 if let Some(event) = event {
340 on_press.call(event);
341 }
342 }
343 })
344 .on_key_down(move |e: Event<KeyboardEventData>| {
345 if e.is_press_event() {
346 on_press.call(e.map(PressEventData::Keyboard))
347 }
348 })
349 }
350
351 fn on_secondary_down(
355 self,
356 on_secondary_down: impl Into<EventHandler<Event<PressEventData>>>,
357 ) -> Self {
358 let on_secondary_down = on_secondary_down.into();
359 self.on_pointer_down(move |e: Event<PointerEventData>| {
360 let event = e.try_map(|d| match d {
361 PointerEventData::Mouse(m) if m.button == Some(MouseButton::Right) => {
362 Some(PressEventData::Mouse(m))
363 }
364 _ => None,
365 });
366 if let Some(event) = event {
367 on_secondary_down.call(event);
368 }
369 })
370 }
371
372 fn on_all_press(self, on_press: impl Into<EventHandler<Event<PressEventData>>>) -> Self {
377 let on_press = on_press.into();
378 self.on_pointer_press({
379 let on_press = on_press.clone();
380 move |e: Event<PointerEventData>| {
381 let event = e.map(|d| match d {
382 PointerEventData::Mouse(m) => PressEventData::Mouse(m),
383 PointerEventData::Touch(t) => PressEventData::Touch(t),
384 });
385 on_press.call(event);
386 }
387 })
388 .on_key_down(move |e: Event<KeyboardEventData>| {
389 if e.is_press_event() {
390 on_press.call(e.map(PressEventData::Keyboard))
391 }
392 })
393 }
394 fn on_focus_press(
400 self,
401 on_focus_press: impl Into<EventHandler<Event<FocusPressEventData>>>,
402 ) -> Self {
403 let on_focus_press = on_focus_press.into();
404 if cfg!(target_os = "android") {
405 self.on_pointer_press(move |e: Event<PointerEventData>| {
406 let event = e.try_map(|d| match d {
407 PointerEventData::Mouse(m) if m.button == Some(MouseButton::Left) => {
408 Some(FocusPressEventData::Mouse(m))
409 }
410 PointerEventData::Touch(t) => Some(FocusPressEventData::Touch(t)),
411 _ => None,
412 });
413 if let Some(event) = event {
414 on_focus_press.call(event);
415 }
416 })
417 } else {
418 self.on_pointer_down(move |e: Event<PointerEventData>| {
419 let event = e.try_map(|d| match d {
420 PointerEventData::Mouse(m) if m.button == Some(MouseButton::Left) => {
421 Some(FocusPressEventData::Mouse(m))
422 }
423 PointerEventData::Touch(t) => Some(FocusPressEventData::Touch(t)),
424 _ => None,
425 });
426 if let Some(event) = event {
427 on_focus_press.call(event);
428 }
429 })
430 }
431 }
432}
433
434#[derive(Debug, Clone, PartialEq)]
436pub enum FocusPressEventData {
437 Mouse(MouseEventData),
438 Touch(TouchEventData),
439}
440
441impl FocusPressEventData {
442 pub fn global_location(&self) -> CursorPoint {
443 match self {
444 Self::Mouse(m) => m.global_location,
445 Self::Touch(t) => t.global_location,
446 }
447 }
448
449 pub fn element_location(&self) -> CursorPoint {
450 match self {
451 Self::Mouse(m) => m.element_location,
452 Self::Touch(t) => t.element_location,
453 }
454 }
455
456 pub fn button(&self) -> Option<MouseButton> {
457 match self {
458 Self::Mouse(m) => m.button,
459 Self::Touch(_) => None,
460 }
461 }
462}
463
464#[derive(Debug, Clone, PartialEq)]
466pub enum PressEventData {
467 Mouse(MouseEventData),
468 Keyboard(KeyboardEventData),
469 Touch(TouchEventData),
470}
471
472pub trait ContainerWithContentExt
474where
475 Self: LayoutExt,
476{
477 fn direction(mut self, direction: Direction) -> Self {
479 self.get_layout().layout.direction = direction;
480 self
481 }
482 fn main_align(mut self, main_align: impl Into<Alignment>) -> Self {
484 self.get_layout().layout.main_alignment = main_align.into();
485 self
486 }
487
488 fn cross_align(mut self, cross_align: impl Into<Alignment>) -> Self {
490 self.get_layout().layout.cross_alignment = cross_align.into();
491 self
492 }
493
494 fn spacing(mut self, spacing: f32) -> Self {
496 self.get_layout().layout.spacing = Length::new(spacing);
497 self
498 }
499
500 fn content(mut self, content: Content) -> Self {
502 self.get_layout().layout.content = content;
503 self
504 }
505 fn center(mut self) -> Self {
507 self.get_layout().layout.main_alignment = Alignment::Center;
508 self.get_layout().layout.cross_alignment = Alignment::Center;
509
510 self
511 }
512
513 fn offset_x(mut self, offset_x: f32) -> Self {
515 self.get_layout().layout.offset_x = Length::new(offset_x);
516 self
517 }
518
519 fn offset_y(mut self, offset_y: f32) -> Self {
521 self.get_layout().layout.offset_y = Length::new(offset_y);
522 self
523 }
524
525 fn vertical(mut self) -> Self {
527 self.get_layout().layout.direction = Direction::vertical();
528 self
529 }
530
531 fn horizontal(mut self) -> Self {
533 self.get_layout().layout.direction = Direction::horizontal();
534 self
535 }
536}
537
538pub trait ContainerSizeExt
540where
541 Self: LayoutExt,
542{
543 fn width(mut self, width: impl Into<Size>) -> Self {
545 self.get_layout().layout.width = width.into();
546 self
547 }
548
549 fn height(mut self, height: impl Into<Size>) -> Self {
551 self.get_layout().layout.height = height.into();
552 self
553 }
554
555 fn expanded(mut self) -> Self {
557 self.get_layout().layout.width = Size::fill();
558 self.get_layout().layout.height = Size::fill();
559 self
560 }
561}
562
563impl<T: ContainerExt> ContainerSizeExt for T {}
564
565pub trait ContainerPositionExt
567where
568 Self: LayoutExt,
569{
570 fn position(mut self, position: impl Into<Position>) -> Self {
572 self.get_layout().layout.position = position.into();
573 self
574 }
575
576 fn margin(mut self, margin: impl Into<Gaps>) -> Self {
578 self.get_layout().layout.margin = margin.into();
579 self
580 }
581}
582
583impl<T: ContainerExt> ContainerPositionExt for T {}
584
585pub trait ContainerExt
587where
588 Self: LayoutExt,
589{
590 fn padding(mut self, padding: impl Into<Gaps>) -> Self {
592 self.get_layout().layout.padding = padding.into();
593 self
594 }
595}
596
597pub trait ContainerConstraintsExt
599where
600 Self: LayoutExt,
601{
602 fn min_width(mut self, minimum_width: impl Into<Size>) -> Self {
604 self.get_layout().layout.minimum_width = minimum_width.into();
605 self
606 }
607
608 fn min_height(mut self, minimum_height: impl Into<Size>) -> Self {
610 self.get_layout().layout.minimum_height = minimum_height.into();
611 self
612 }
613
614 fn max_width(mut self, maximum_width: impl Into<Size>) -> Self {
616 self.get_layout().layout.maximum_width = maximum_width.into();
617 self
618 }
619
620 fn max_height(mut self, maximum_height: impl Into<Size>) -> Self {
622 self.get_layout().layout.maximum_height = maximum_height.into();
623 self
624 }
625
626 fn visible_width(mut self, visible_width: impl Into<VisibleSize>) -> Self {
628 self.get_layout().layout.visible_width = visible_width.into();
629 self
630 }
631
632 fn visible_height(mut self, visible_height: impl Into<VisibleSize>) -> Self {
634 self.get_layout().layout.visible_height = visible_height.into();
635 self
636 }
637}
638
639impl<T: ContainerExt> ContainerConstraintsExt for T {}
640
641pub trait LayoutExt
643where
644 Self: Sized,
645{
646 fn get_layout(&mut self) -> &mut LayoutData;
648
649 fn layout(mut self, layout: LayoutData) -> Self {
651 *self.get_layout() = layout;
652 self
653 }
654}
655
656pub trait ImageExt
658where
659 Self: LayoutExt,
660{
661 fn get_image_data(&mut self) -> &mut ImageData;
663
664 fn image_data(mut self, image_data: ImageData) -> Self {
666 *self.get_image_data() = image_data;
667 self
668 }
669
670 fn sampling_mode(mut self, sampling_mode: SamplingMode) -> Self {
672 self.get_image_data().sampling_mode = sampling_mode;
673 self
674 }
675
676 fn aspect_ratio(mut self, aspect_ratio: AspectRatio) -> Self {
678 self.get_image_data().aspect_ratio = aspect_ratio;
679 self
680 }
681
682 fn image_cover(mut self, image_cover: ImageCover) -> Self {
684 self.get_image_data().image_cover = image_cover;
685 self
686 }
687}
688
689pub trait AccessibilityExt: Sized {
691 fn get_accessibility_data(&mut self) -> &mut AccessibilityData;
693
694 fn accessibility(mut self, accessibility: AccessibilityData) -> Self {
696 *self.get_accessibility_data() = accessibility;
697 self
698 }
699
700 fn a11y_id(mut self, a11y_id: impl Into<Option<AccessibilityId>>) -> Self {
702 self.get_accessibility_data().a11y_id = a11y_id.into();
703 self
704 }
705
706 fn a11y_focusable(mut self, a11y_focusable: impl Into<Focusable>) -> Self {
708 self.get_accessibility_data().a11y_focusable = a11y_focusable.into();
709 self
710 }
711
712 fn a11y_auto_focus(mut self, a11y_auto_focus: impl Into<bool>) -> Self {
714 self.get_accessibility_data().a11y_auto_focus = a11y_auto_focus.into();
715 self
716 }
717
718 fn a11y_member_of(mut self, a11y_member_of: impl Into<AccessibilityId>) -> Self {
720 self.get_accessibility_data()
721 .builder
722 .set_member_of(a11y_member_of.into());
723 self
724 }
725
726 fn a11y_role(mut self, a11y_role: impl Into<AccessibilityRole>) -> Self {
728 self.get_accessibility_data()
729 .builder
730 .set_role(a11y_role.into());
731 self
732 }
733
734 fn a11y_alt(mut self, value: impl Into<Box<str>>) -> Self {
736 self.get_accessibility_data().builder.set_label(value);
737 self
738 }
739
740 fn a11y_builder(mut self, with: impl FnOnce(&mut accesskit::Node)) -> Self {
742 with(&mut self.get_accessibility_data().builder);
743 self
744 }
745}
746
747pub trait TextStyleExt
749where
750 Self: Sized,
751{
752 fn get_text_style_data(&mut self) -> &mut TextStyleData;
754
755 fn text_style(mut self, data: TextStyleData) -> Self {
757 *self.get_text_style_data() = data;
758 self
759 }
760
761 fn color(mut self, color: impl Into<Fill>) -> Self {
763 self.get_text_style_data().color = Some(color.into());
764 self
765 }
766
767 fn text_align(mut self, text_align: impl Into<TextAlign>) -> Self {
769 self.get_text_style_data().text_align = Some(text_align.into());
770 self
771 }
772
773 fn font_size(mut self, font_size: impl Into<FontSize>) -> Self {
775 self.get_text_style_data().font_size = Some(font_size.into());
776 self
777 }
778
779 fn font_family(mut self, font_family: impl Into<Cow<'static, str>>) -> Self {
781 self.get_text_style_data()
782 .font_families
783 .push(font_family.into());
784 self
785 }
786
787 fn font_slant(mut self, font_slant: impl Into<FontSlant>) -> Self {
789 self.get_text_style_data().font_slant = Some(font_slant.into());
790 self
791 }
792
793 fn font_weight(mut self, font_weight: impl Into<FontWeight>) -> Self {
795 self.get_text_style_data().font_weight = Some(font_weight.into());
796 self
797 }
798
799 fn font_width(mut self, font_width: impl Into<FontWidth>) -> Self {
801 self.get_text_style_data().font_width = Some(font_width.into());
802 self
803 }
804
805 fn text_height(mut self, text_height: impl Into<TextHeightBehavior>) -> Self {
807 self.get_text_style_data().text_height = Some(text_height.into());
808 self
809 }
810
811 fn text_overflow(mut self, text_overflow: impl Into<TextOverflow>) -> Self {
813 self.get_text_style_data().text_overflow = Some(text_overflow.into());
814 self
815 }
816
817 fn text_shadow(mut self, text_shadow: impl Into<TextShadow>) -> Self {
819 self.get_text_style_data()
820 .text_shadows
821 .push(text_shadow.into());
822 self
823 }
824
825 fn text_decoration(mut self, text_decoration: impl Into<TextDecoration>) -> Self {
827 self.get_text_style_data().text_decoration = Some(text_decoration.into());
828 self
829 }
830}
831
832pub trait StyleExt
834where
835 Self: Sized,
836{
837 fn get_style(&mut self) -> &mut StyleState;
839
840 fn style(mut self, style: StyleState) -> Self {
842 *self.get_style() = style;
843 self
844 }
845
846 fn background(mut self, background: impl Into<Fill>) -> Self {
848 self.get_style().background = background.into();
849 self
850 }
851
852 fn border(mut self, border: impl Into<Option<Border>>) -> Self {
854 if let Some(border) = border.into() {
855 self.get_style().borders.push(border);
856 }
857 self
858 }
859
860 fn shadow(mut self, shadow: impl Into<Shadow>) -> Self {
862 self.get_style().shadows.push(shadow.into());
863 self
864 }
865
866 fn corner_radius(mut self, corner_radius: impl Into<CornerRadius>) -> Self {
868 self.get_style().corner_radius = corner_radius.into();
869 self
870 }
871}
872
873impl<T: StyleExt> CornerRadiusExt for T {
874 fn with_corner_radius(mut self, corner_radius: f32) -> Self {
875 self.get_style().corner_radius = CornerRadius::new_all(corner_radius);
876 self
877 }
878}
879
880pub trait CornerRadiusExt: Sized {
882 fn with_corner_radius(self, corner_radius: f32) -> Self;
884
885 fn rounded_none(self) -> Self {
887 self.with_corner_radius(0.)
888 }
889
890 fn rounded(self) -> Self {
892 self.with_corner_radius(6.)
893 }
894
895 fn rounded_sm(self) -> Self {
897 self.with_corner_radius(4.)
898 }
899
900 fn rounded_md(self) -> Self {
902 self.with_corner_radius(6.)
903 }
904
905 fn rounded_lg(self) -> Self {
907 self.with_corner_radius(8.)
908 }
909
910 fn rounded_xl(self) -> Self {
912 self.with_corner_radius(12.)
913 }
914
915 fn rounded_2xl(self) -> Self {
917 self.with_corner_radius(16.)
918 }
919
920 fn rounded_3xl(self) -> Self {
922 self.with_corner_radius(24.)
923 }
924
925 fn rounded_4xl(self) -> Self {
927 self.with_corner_radius(32.)
928 }
929
930 fn rounded_full(self) -> Self {
932 self.with_corner_radius(99.)
933 }
934}
935
936pub trait MaybeExt
938where
939 Self: Sized,
940{
941 fn maybe(self, bool: impl Into<bool>, then: impl FnOnce(Self) -> Self) -> Self {
943 if bool.into() { then(self) } else { self }
944 }
945
946 fn map<T>(self, data: Option<T>, then: impl FnOnce(Self, T) -> Self) -> Self {
948 if let Some(data) = data {
949 then(self, data)
950 } else {
951 self
952 }
953 }
954}
955
956pub trait LayerExt
958where
959 Self: Sized,
960{
961 fn get_layer(&mut self) -> &mut Layer;
963
964 fn layer(mut self, layer: impl Into<Layer>) -> Self {
966 *self.get_layer() = layer.into();
967 self
968 }
969}
970
971pub trait ScrollableExt
972where
973 Self: Sized,
974{
975 fn get_effect(&mut self) -> &mut EffectData;
977
978 fn scrollable(mut self, scrollable: impl Into<bool>) -> Self {
981 self.get_effect().scrollable = scrollable.into();
982 self
983 }
984}
985
986pub trait InteractiveExt
988where
989 Self: Sized,
990{
991 fn get_effect(&mut self) -> &mut EffectData;
993
994 fn interactive(mut self, interactive: impl Into<Interactive>) -> Self {
996 self.get_effect().interactive = interactive.into();
997 self
998 }
999}
1000
1001pub trait EffectExt: Sized {
1003 fn get_effect(&mut self) -> &mut EffectData;
1005
1006 fn effect(mut self, effect: EffectData) -> Self {
1008 *self.get_effect() = effect;
1009 self
1010 }
1011
1012 fn overflow(mut self, overflow: impl Into<Overflow>) -> Self {
1014 self.get_effect().overflow = overflow.into();
1015 self
1016 }
1017
1018 fn blur(mut self, blur: f32) -> Self {
1020 self.get_effect().blur = Some(blur);
1021 self
1022 }
1023
1024 fn rotation(mut self, rotation: f32) -> Self {
1026 self.get_effect().rotation = Some(rotation);
1027 self
1028 }
1029
1030 fn opacity(mut self, opacity: f32) -> Self {
1032 self.get_effect().opacity = Some(opacity);
1033 self
1034 }
1035
1036 fn scale(mut self, scale: impl Into<Scale>) -> Self {
1038 self.get_effect().scale = Some(scale.into());
1039 self
1040 }
1041
1042 fn transform_origin(mut self, transform_origin: impl Into<TransformOrigin>) -> Self {
1046 self.get_effect().transform_origin = transform_origin.into();
1047 self
1048 }
1049}