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 StyledEventData,
55 WheelEventData,
56 },
57 name::EventName,
58 },
59 layers::Layer,
60 prelude::*,
61 style::{
62 font_size::FontSize,
63 font_slant::FontSlant,
64 font_weight::FontWeight,
65 font_width::FontWidth,
66 scale::Scale,
67 text_height::TextHeightBehavior,
68 text_overflow::TextOverflow,
69 text_shadow::TextShadow,
70 transform_origin::TransformOrigin,
71 },
72};
73
74pub trait ChildrenExt: Sized {
76 fn get_children(&mut self) -> &mut Vec<Element>;
87
88 fn children(mut self, children: impl IntoIterator<Item = Element>) -> Self {
95 self.get_children().extend(children);
96 self
97 }
98
99 fn maybe_child<C: IntoElement>(mut self, child: Option<C>) -> Self {
106 if let Some(child) = child {
107 self.get_children().push(child.into_element());
108 }
109 self
110 }
111
112 fn child<C: IntoElement>(mut self, child: C) -> Self {
119 self.get_children().push(child.into_element());
120 self
121 }
122}
123
124pub trait KeyExt: Sized {
126 fn write_key(&mut self) -> &mut DiffKey;
128
129 fn key(mut self, key: impl Hash) -> Self
133 where
134 Self: 'static,
135 {
136 let mut hasher = FxHasher::default();
137 std::any::TypeId::of::<Self>().hash(&mut hasher);
138 key.hash(&mut hasher);
139 *self.write_key() = DiffKey::U64(hasher.finish());
140 self
141 }
142}
143
144pub trait ListExt {
146 fn with(self, other: Self) -> Self;
148}
149
150impl<T> ListExt for Vec<T> {
151 fn with(mut self, other: Self) -> Self {
152 self.extend(other);
153 self
154 }
155}
156
157macro_rules! event_handlers {
158 (
159 $handler_variant:ident, $event_data:ty;
160 $(
161 $(#[$attr:meta])*
162 $name:ident => $event_variant:expr ;
163 )*
164 ) => {
165 paste! {
166 $(
167 $(#[$attr])*
168 fn [<on_$name>](mut self, [<on_$name>]: impl Into<EventHandler<Event<$event_data>>>) -> Self {
169 self.get_event_handlers()
170 .insert($event_variant, EventHandlerType::$handler_variant([<on_$name>].into()));
171 self
172 }
173 )*
174 }
175 };
176}
177
178pub trait EventHandlersExt: Sized {
186 fn get_event_handlers(&mut self) -> &mut FxHashMap<EventName, EventHandlerType>;
188
189 fn with_event_handlers(
191 mut self,
192 event_handlers: FxHashMap<EventName, EventHandlerType>,
193 ) -> Self {
194 *self.get_event_handlers() = event_handlers;
195 self
196 }
197
198 event_handlers! {
199 Mouse,
200 MouseEventData;
201
202 mouse_down => EventName::MouseDown;
204 mouse_up => EventName::MouseUp;
206 mouse_move => EventName::MouseMove;
208
209 }
210
211 event_handlers! {
212 Pointer,
213 PointerEventData;
214
215 global_pointer_press => EventName::GlobalPointerPress;
217 global_pointer_down => EventName::GlobalPointerDown;
219 global_pointer_move => EventName::GlobalPointerMove;
221
222 capture_global_pointer_move => EventName::CaptureGlobalPointerMove;
224 capture_global_pointer_press => EventName::CaptureGlobalPointerPress;
226 }
227
228 event_handlers! {
229 Keyboard,
230 KeyboardEventData;
231
232 key_down => EventName::KeyDown;
234 key_up => EventName::KeyUp;
236
237 global_key_down => EventName::GlobalKeyDown;
239 global_key_up => EventName::GlobalKeyUp;
241 }
242
243 event_handlers! {
244 Wheel,
245 WheelEventData;
246
247 wheel => EventName::Wheel;
249 }
250
251 event_handlers! {
252 Touch,
253 TouchEventData;
254
255 touch_cancel => EventName::TouchCancel;
257 touch_start => EventName::TouchStart;
259 touch_move => EventName::TouchMove;
261 touch_end => EventName::TouchEnd;
263 }
264
265 event_handlers! {
266 Pointer,
267 PointerEventData;
268
269 pointer_press => EventName::PointerPress;
271 pointer_down => EventName::PointerDown;
273 pointer_move => EventName::PointerMove;
275 pointer_enter => EventName::PointerEnter;
277 pointer_leave => EventName::PointerLeave;
279 pointer_over => EventName::PointerOver;
281 pointer_out => EventName::PointerOut;
283 }
284
285 event_handlers! {
286 File,
287 FileEventData;
288
289 file_drop => EventName::FileDrop;
291 global_file_hover => EventName::GlobalFileHover;
293 global_file_hover_cancelled => EventName::GlobalFileHoverCancelled;
295 }
296
297 event_handlers! {
298 ImePreedit,
299 ImePreeditEventData;
300
301 ime_preedit => EventName::ImePreedit;
303 }
304
305 fn on_sized(mut self, on_sized: impl Into<EventHandler<Event<SizedEventData>>>) -> Self
307 where
308 Self: LayoutExt,
309 {
310 self.get_event_handlers()
311 .insert(EventName::Sized, EventHandlerType::Sized(on_sized.into()));
312 self.get_layout().layout.has_layout_references = true;
313 self
314 }
315
316 fn on_styled(mut self, on_styled: impl Into<EventHandler<Event<StyledEventData>>>) -> Self {
318 self.get_event_handlers().insert(
319 EventName::Styled,
320 EventHandlerType::Styled(on_styled.into()),
321 );
322 self
323 }
324
325 fn on_press(self, on_press: impl Into<EventHandler<Event<PressEventData>>>) -> Self {
332 let on_press = on_press.into();
333 self.on_pointer_press({
334 let on_press = on_press.clone();
335 move |e: Event<PointerEventData>| {
336 let event = e.try_map(|d| match d {
337 PointerEventData::Mouse(m) if m.button == Some(MouseButton::Left) => {
338 Some(PressEventData::Mouse(m))
339 }
340 PointerEventData::Touch(t) => Some(PressEventData::Touch(t)),
341 _ => None,
342 });
343 if let Some(event) = event {
344 on_press.call(event);
345 }
346 }
347 })
348 .on_key_down(move |e: Event<KeyboardEventData>| {
349 if e.is_press_event() {
350 on_press.call(e.map(PressEventData::Keyboard))
351 }
352 })
353 }
354
355 fn on_secondary_down(
359 self,
360 on_secondary_down: impl Into<EventHandler<Event<PressEventData>>>,
361 ) -> Self {
362 let on_secondary_down = on_secondary_down.into();
363 self.on_pointer_down(move |e: Event<PointerEventData>| {
364 let event = e.try_map(|d| match d {
365 PointerEventData::Mouse(m) if m.button == Some(MouseButton::Right) => {
366 Some(PressEventData::Mouse(m))
367 }
368 _ => None,
369 });
370 if let Some(event) = event {
371 on_secondary_down.call(event);
372 }
373 })
374 }
375
376 fn on_all_press(self, on_press: impl Into<EventHandler<Event<PressEventData>>>) -> Self {
381 let on_press = on_press.into();
382 self.on_pointer_press({
383 let on_press = on_press.clone();
384 move |e: Event<PointerEventData>| {
385 let event = e.map(|d| match d {
386 PointerEventData::Mouse(m) => PressEventData::Mouse(m),
387 PointerEventData::Touch(t) => PressEventData::Touch(t),
388 });
389 on_press.call(event);
390 }
391 })
392 .on_key_down(move |e: Event<KeyboardEventData>| {
393 if e.is_press_event() {
394 on_press.call(e.map(PressEventData::Keyboard))
395 }
396 })
397 }
398 fn on_focus_press(
404 self,
405 on_focus_press: impl Into<EventHandler<Event<FocusPressEventData>>>,
406 ) -> Self {
407 let on_focus_press = on_focus_press.into();
408 if cfg!(target_os = "android") {
409 self.on_pointer_press(move |e: Event<PointerEventData>| {
410 let event = e.try_map(|d| match d {
411 PointerEventData::Mouse(m) if m.button == Some(MouseButton::Left) => {
412 Some(FocusPressEventData::Mouse(m))
413 }
414 PointerEventData::Touch(t) => Some(FocusPressEventData::Touch(t)),
415 _ => None,
416 });
417 if let Some(event) = event {
418 on_focus_press.call(event);
419 }
420 })
421 } else {
422 self.on_pointer_down(move |e: Event<PointerEventData>| {
423 let event = e.try_map(|d| match d {
424 PointerEventData::Mouse(m) if m.button == Some(MouseButton::Left) => {
425 Some(FocusPressEventData::Mouse(m))
426 }
427 PointerEventData::Touch(t) => Some(FocusPressEventData::Touch(t)),
428 _ => None,
429 });
430 if let Some(event) = event {
431 on_focus_press.call(event);
432 }
433 })
434 }
435 }
436}
437
438#[derive(Debug, Clone, PartialEq)]
440pub enum FocusPressEventData {
441 Mouse(MouseEventData),
442 Touch(TouchEventData),
443}
444
445impl FocusPressEventData {
446 pub fn global_location(&self) -> CursorPoint {
447 match self {
448 Self::Mouse(m) => m.global_location,
449 Self::Touch(t) => t.global_location,
450 }
451 }
452
453 pub fn element_location(&self) -> CursorPoint {
454 match self {
455 Self::Mouse(m) => m.element_location,
456 Self::Touch(t) => t.element_location,
457 }
458 }
459
460 pub fn button(&self) -> Option<MouseButton> {
461 match self {
462 Self::Mouse(m) => m.button,
463 Self::Touch(_) => None,
464 }
465 }
466}
467
468#[derive(Debug, Clone, PartialEq)]
470pub enum PressEventData {
471 Mouse(MouseEventData),
472 Keyboard(KeyboardEventData),
473 Touch(TouchEventData),
474}
475
476pub trait ContainerWithContentExt
478where
479 Self: LayoutExt,
480{
481 fn direction(mut self, direction: Direction) -> Self {
483 self.get_layout().layout.direction = direction;
484 self
485 }
486 fn main_align(mut self, main_align: Alignment) -> Self {
488 self.get_layout().layout.main_alignment = main_align;
489 self
490 }
491
492 fn cross_align(mut self, cross_align: Alignment) -> Self {
494 self.get_layout().layout.cross_alignment = cross_align;
495 self
496 }
497
498 fn spacing(mut self, spacing: f32) -> Self {
500 self.get_layout().layout.spacing = Length::new(spacing);
501 self
502 }
503
504 fn content(mut self, content: Content) -> Self {
506 self.get_layout().layout.content = content;
507 self
508 }
509 fn center(mut self) -> Self {
511 self.get_layout().layout.main_alignment = Alignment::Center;
512 self.get_layout().layout.cross_alignment = Alignment::Center;
513
514 self
515 }
516
517 fn offset_x(mut self, offset_x: f32) -> Self {
519 self.get_layout().layout.offset_x = Length::new(offset_x);
520 self
521 }
522
523 fn offset_y(mut self, offset_y: f32) -> Self {
525 self.get_layout().layout.offset_y = Length::new(offset_y);
526 self
527 }
528
529 fn vertical(mut self) -> Self {
531 self.get_layout().layout.direction = Direction::vertical();
532 self
533 }
534
535 fn horizontal(mut self) -> Self {
537 self.get_layout().layout.direction = Direction::horizontal();
538 self
539 }
540}
541
542pub trait ContainerSizeExt
544where
545 Self: LayoutExt,
546{
547 fn width(mut self, width: impl Into<Size>) -> Self {
549 self.get_layout().layout.width = width.into();
550 self
551 }
552
553 fn height(mut self, height: impl Into<Size>) -> Self {
555 self.get_layout().layout.height = height.into();
556 self
557 }
558
559 fn expanded(mut self) -> Self {
561 self.get_layout().layout.width = Size::fill();
562 self.get_layout().layout.height = Size::fill();
563 self
564 }
565}
566
567impl<T: ContainerExt> ContainerSizeExt for T {}
568
569pub trait ContainerPositionExt
571where
572 Self: LayoutExt,
573{
574 fn position(mut self, position: impl Into<Position>) -> Self {
576 self.get_layout().layout.position = position.into();
577 self
578 }
579
580 fn margin(mut self, margin: impl Into<Gaps>) -> Self {
582 self.get_layout().layout.margin = margin.into();
583 self
584 }
585}
586
587impl<T: ContainerExt> ContainerPositionExt for T {}
588
589pub trait ContainerExt
591where
592 Self: LayoutExt,
593{
594 fn padding(mut self, padding: impl Into<Gaps>) -> Self {
596 self.get_layout().layout.padding = padding.into();
597 self
598 }
599
600 fn min_width(mut self, minimum_width: impl Into<Size>) -> Self {
602 self.get_layout().layout.minimum_width = minimum_width.into();
603 self
604 }
605
606 fn min_height(mut self, minimum_height: impl Into<Size>) -> Self {
608 self.get_layout().layout.minimum_height = minimum_height.into();
609 self
610 }
611
612 fn max_width(mut self, maximum_width: impl Into<Size>) -> Self {
614 self.get_layout().layout.maximum_width = maximum_width.into();
615 self
616 }
617
618 fn max_height(mut self, maximum_height: impl Into<Size>) -> Self {
620 self.get_layout().layout.maximum_height = maximum_height.into();
621 self
622 }
623
624 fn visible_width(mut self, visible_width: impl Into<VisibleSize>) -> Self {
626 self.get_layout().layout.visible_width = visible_width.into();
627 self
628 }
629
630 fn visible_height(mut self, visible_height: impl Into<VisibleSize>) -> Self {
632 self.get_layout().layout.visible_height = visible_height.into();
633 self
634 }
635}
636
637pub trait LayoutExt
639where
640 Self: Sized,
641{
642 fn get_layout(&mut self) -> &mut LayoutData;
644
645 fn layout(mut self, layout: LayoutData) -> Self {
647 *self.get_layout() = layout;
648 self
649 }
650}
651
652pub trait ImageExt
654where
655 Self: LayoutExt,
656{
657 fn get_image_data(&mut self) -> &mut ImageData;
659
660 fn image_data(mut self, image_data: ImageData) -> Self {
662 *self.get_image_data() = image_data;
663 self
664 }
665
666 fn sampling_mode(mut self, sampling_mode: SamplingMode) -> Self {
668 self.get_image_data().sampling_mode = sampling_mode;
669 self
670 }
671
672 fn aspect_ratio(mut self, aspect_ratio: AspectRatio) -> Self {
674 self.get_image_data().aspect_ratio = aspect_ratio;
675 self
676 }
677
678 fn image_cover(mut self, image_cover: ImageCover) -> Self {
680 self.get_image_data().image_cover = image_cover;
681 self
682 }
683}
684
685pub trait AccessibilityExt: Sized {
687 fn get_accessibility_data(&mut self) -> &mut AccessibilityData;
689
690 fn accessibility(mut self, accessibility: AccessibilityData) -> Self {
692 *self.get_accessibility_data() = accessibility;
693 self
694 }
695
696 fn a11y_id(mut self, a11y_id: impl Into<Option<AccessibilityId>>) -> Self {
698 self.get_accessibility_data().a11y_id = a11y_id.into();
699 self
700 }
701
702 fn a11y_focusable(mut self, a11y_focusable: impl Into<Focusable>) -> Self {
704 self.get_accessibility_data().a11y_focusable = a11y_focusable.into();
705 self
706 }
707
708 fn a11y_auto_focus(mut self, a11y_auto_focus: impl Into<bool>) -> Self {
710 self.get_accessibility_data().a11y_auto_focus = a11y_auto_focus.into();
711 self
712 }
713
714 fn a11y_member_of(mut self, a11y_member_of: impl Into<AccessibilityId>) -> Self {
716 self.get_accessibility_data()
717 .builder
718 .set_member_of(a11y_member_of.into());
719 self
720 }
721
722 fn a11y_role(mut self, a11y_role: impl Into<AccessibilityRole>) -> Self {
724 self.get_accessibility_data()
725 .builder
726 .set_role(a11y_role.into());
727 self
728 }
729
730 fn a11y_alt(mut self, value: impl Into<Box<str>>) -> Self {
732 self.get_accessibility_data().builder.set_label(value);
733 self
734 }
735
736 fn a11y_builder(mut self, with: impl FnOnce(&mut accesskit::Node)) -> Self {
738 with(&mut self.get_accessibility_data().builder);
739 self
740 }
741}
742
743pub trait TextStyleExt
745where
746 Self: Sized,
747{
748 fn get_text_style_data(&mut self) -> &mut TextStyleData;
750
751 fn text_style(mut self, data: TextStyleData) -> Self {
753 *self.get_text_style_data() = data;
754 self
755 }
756
757 fn color(mut self, color: impl Into<Fill>) -> Self {
759 self.get_text_style_data().color = Some(color.into());
760 self
761 }
762
763 fn text_align(mut self, text_align: impl Into<TextAlign>) -> Self {
765 self.get_text_style_data().text_align = Some(text_align.into());
766 self
767 }
768
769 fn font_size(mut self, font_size: impl Into<FontSize>) -> Self {
771 self.get_text_style_data().font_size = Some(font_size.into());
772 self
773 }
774
775 fn font_family(mut self, font_family: impl Into<Cow<'static, str>>) -> Self {
777 self.get_text_style_data()
778 .font_families
779 .push(font_family.into());
780 self
781 }
782
783 fn font_slant(mut self, font_slant: impl Into<FontSlant>) -> Self {
785 self.get_text_style_data().font_slant = Some(font_slant.into());
786 self
787 }
788
789 fn font_weight(mut self, font_weight: impl Into<FontWeight>) -> Self {
791 self.get_text_style_data().font_weight = Some(font_weight.into());
792 self
793 }
794
795 fn font_width(mut self, font_width: impl Into<FontWidth>) -> Self {
797 self.get_text_style_data().font_width = Some(font_width.into());
798 self
799 }
800
801 fn text_height(mut self, text_height: impl Into<TextHeightBehavior>) -> Self {
803 self.get_text_style_data().text_height = Some(text_height.into());
804 self
805 }
806
807 fn text_overflow(mut self, text_overflow: impl Into<TextOverflow>) -> Self {
809 self.get_text_style_data().text_overflow = Some(text_overflow.into());
810 self
811 }
812
813 fn text_shadow(mut self, text_shadow: impl Into<TextShadow>) -> Self {
815 self.get_text_style_data()
816 .text_shadows
817 .push(text_shadow.into());
818 self
819 }
820
821 fn text_decoration(mut self, text_decoration: impl Into<TextDecoration>) -> Self {
823 self.get_text_style_data().text_decoration = Some(text_decoration.into());
824 self
825 }
826}
827
828pub trait StyleExt
830where
831 Self: Sized,
832{
833 fn get_style(&mut self) -> &mut StyleState;
835
836 fn background(mut self, background: impl Into<Fill>) -> Self {
838 self.get_style().background = background.into();
839 self
840 }
841
842 fn border(mut self, border: impl Into<Option<Border>>) -> Self {
844 if let Some(border) = border.into() {
845 self.get_style().borders.push(border);
846 }
847 self
848 }
849
850 fn shadow(mut self, shadow: impl Into<Shadow>) -> Self {
852 self.get_style().shadows.push(shadow.into());
853 self
854 }
855
856 fn corner_radius(mut self, corner_radius: impl Into<CornerRadius>) -> Self {
858 self.get_style().corner_radius = corner_radius.into();
859 self
860 }
861}
862
863impl<T: StyleExt> CornerRadiusExt for T {
864 fn with_corner_radius(mut self, corner_radius: f32) -> Self {
865 self.get_style().corner_radius = CornerRadius::new_all(corner_radius);
866 self
867 }
868}
869
870pub trait CornerRadiusExt: Sized {
872 fn with_corner_radius(self, corner_radius: f32) -> Self;
874
875 fn rounded_none(self) -> Self {
877 self.with_corner_radius(0.)
878 }
879
880 fn rounded(self) -> Self {
882 self.with_corner_radius(6.)
883 }
884
885 fn rounded_sm(self) -> Self {
887 self.with_corner_radius(4.)
888 }
889
890 fn rounded_md(self) -> Self {
892 self.with_corner_radius(6.)
893 }
894
895 fn rounded_lg(self) -> Self {
897 self.with_corner_radius(8.)
898 }
899
900 fn rounded_xl(self) -> Self {
902 self.with_corner_radius(12.)
903 }
904
905 fn rounded_2xl(self) -> Self {
907 self.with_corner_radius(16.)
908 }
909
910 fn rounded_3xl(self) -> Self {
912 self.with_corner_radius(24.)
913 }
914
915 fn rounded_4xl(self) -> Self {
917 self.with_corner_radius(32.)
918 }
919
920 fn rounded_full(self) -> Self {
922 self.with_corner_radius(99.)
923 }
924}
925
926pub trait MaybeExt
928where
929 Self: Sized,
930{
931 fn maybe(self, bool: impl Into<bool>, then: impl FnOnce(Self) -> Self) -> Self {
933 if bool.into() { then(self) } else { self }
934 }
935
936 fn map<T>(self, data: Option<T>, then: impl FnOnce(Self, T) -> Self) -> Self {
938 if let Some(data) = data {
939 then(self, data)
940 } else {
941 self
942 }
943 }
944}
945
946pub trait LayerExt
948where
949 Self: Sized,
950{
951 fn get_layer(&mut self) -> &mut Layer;
953
954 fn layer(mut self, layer: impl Into<Layer>) -> Self {
956 *self.get_layer() = layer.into();
957 self
958 }
959}
960
961pub trait ScrollableExt
962where
963 Self: Sized,
964{
965 fn get_effect(&mut self) -> &mut EffectData;
967
968 fn scrollable(mut self, scrollable: impl Into<bool>) -> Self {
971 self.get_effect().scrollable = scrollable.into();
972 self
973 }
974}
975
976pub trait InteractiveExt
978where
979 Self: Sized,
980{
981 fn get_effect(&mut self) -> &mut EffectData;
983
984 fn interactive(mut self, interactive: impl Into<Interactive>) -> Self {
986 self.get_effect().interactive = interactive.into();
987 self
988 }
989}
990
991pub trait EffectExt: Sized {
993 fn get_effect(&mut self) -> &mut EffectData;
995
996 fn effect(mut self, effect: EffectData) -> Self {
998 *self.get_effect() = effect;
999 self
1000 }
1001
1002 fn overflow(mut self, overflow: impl Into<Overflow>) -> Self {
1004 self.get_effect().overflow = overflow.into();
1005 self
1006 }
1007
1008 fn blur(mut self, blur: f32) -> Self {
1010 self.get_effect().blur = Some(blur);
1011 self
1012 }
1013
1014 fn rotation(mut self, rotation: f32) -> Self {
1016 self.get_effect().rotation = Some(rotation);
1017 self
1018 }
1019
1020 fn opacity(mut self, opacity: f32) -> Self {
1022 self.get_effect().opacity = Some(opacity);
1023 self
1024 }
1025
1026 fn scale(mut self, scale: impl Into<Scale>) -> Self {
1028 self.get_effect().scale = Some(scale.into());
1029 self
1030 }
1031
1032 fn transform_origin(mut self, transform_origin: impl Into<TransformOrigin>) -> Self {
1036 self.get_effect().transform_origin = transform_origin.into();
1037 self
1038 }
1039}