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 text_height::TextHeightBehavior,
67 text_overflow::TextOverflow,
68 text_shadow::TextShadow,
69 transform_origin::TransformOrigin,
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 {
125 fn write_key(&mut self) -> &mut DiffKey;
127
128 fn key(mut self, key: impl Hash) -> Self {
130 let mut hasher = FxHasher::default();
131 key.hash(&mut hasher);
132 *self.write_key() = DiffKey::U64(hasher.finish());
133 self
134 }
135}
136
137pub trait ListExt {
139 fn with(self, other: Self) -> Self;
141}
142
143impl<T> ListExt for Vec<T> {
144 fn with(mut self, other: Self) -> Self {
145 self.extend(other);
146 self
147 }
148}
149
150macro_rules! event_handlers {
151 (
152 $handler_variant:ident, $event_data:ty;
153 $(
154 $(#[$attr:meta])*
155 $name:ident => $event_variant:expr ;
156 )*
157 ) => {
158 paste! {
159 $(
160 $(#[$attr])*
161 fn [<on_$name>](mut self, [<on_$name>]: impl Into<EventHandler<Event<$event_data>>>) -> Self {
162 self.get_event_handlers()
163 .insert($event_variant, EventHandlerType::$handler_variant([<on_$name>].into()));
164 self
165 }
166 )*
167 }
168 };
169}
170
171pub trait EventHandlersExt: Sized {
179 fn get_event_handlers(&mut self) -> &mut FxHashMap<EventName, EventHandlerType>;
181
182 fn with_event_handlers(
184 mut self,
185 event_handlers: FxHashMap<EventName, EventHandlerType>,
186 ) -> Self {
187 *self.get_event_handlers() = event_handlers;
188 self
189 }
190
191 event_handlers! {
192 Mouse,
193 MouseEventData;
194
195 mouse_down => EventName::MouseDown;
197 mouse_up => EventName::MouseUp;
199 mouse_move => EventName::MouseMove;
201
202 }
203
204 event_handlers! {
205 Pointer,
206 PointerEventData;
207
208 global_pointer_press => EventName::GlobalPointerPress;
210 global_pointer_down => EventName::GlobalPointerDown;
212 global_pointer_move => EventName::GlobalPointerMove;
214
215 capture_global_pointer_move => EventName::CaptureGlobalPointerMove;
217 capture_global_pointer_press => EventName::CaptureGlobalPointerPress;
219 }
220
221 event_handlers! {
222 Keyboard,
223 KeyboardEventData;
224
225 key_down => EventName::KeyDown;
227 key_up => EventName::KeyUp;
229
230 global_key_down => EventName::GlobalKeyDown;
232 global_key_up => EventName::GlobalKeyUp;
234 }
235
236 event_handlers! {
237 Wheel,
238 WheelEventData;
239
240 wheel => EventName::Wheel;
242 }
243
244 event_handlers! {
245 Touch,
246 TouchEventData;
247
248 touch_cancel => EventName::TouchCancel;
250 touch_start => EventName::TouchStart;
252 touch_move => EventName::TouchMove;
254 touch_end => EventName::TouchEnd;
256 }
257
258 event_handlers! {
259 Pointer,
260 PointerEventData;
261
262 pointer_press => EventName::PointerPress;
264 pointer_down => EventName::PointerDown;
266 pointer_move => EventName::PointerMove;
268 pointer_enter => EventName::PointerEnter;
270 pointer_leave => EventName::PointerLeave;
272 pointer_over => EventName::PointerOver;
274 pointer_out => EventName::PointerOut;
276 }
277
278 event_handlers! {
279 File,
280 FileEventData;
281
282 file_drop => EventName::FileDrop;
284 global_file_hover => EventName::GlobalFileHover;
286 global_file_hover_cancelled => EventName::GlobalFileHoverCancelled;
288 }
289
290 event_handlers! {
291 ImePreedit,
292 ImePreeditEventData;
293
294 ime_preedit => EventName::ImePreedit;
296 }
297
298 fn on_sized(mut self, on_sized: impl Into<EventHandler<Event<SizedEventData>>>) -> Self
300 where
301 Self: LayoutExt,
302 {
303 self.get_event_handlers()
304 .insert(EventName::Sized, EventHandlerType::Sized(on_sized.into()));
305 self.get_layout().layout.has_layout_references = true;
306 self
307 }
308
309 fn on_press(self, on_press: impl Into<EventHandler<Event<PressEventData>>>) -> Self {
316 let on_press = on_press.into();
317 self.on_pointer_press({
318 let on_press = on_press.clone();
319 move |e: Event<PointerEventData>| {
320 let event = e.try_map(|d| match d {
321 PointerEventData::Mouse(m) if m.button == Some(MouseButton::Left) => {
322 Some(PressEventData::Mouse(m))
323 }
324 PointerEventData::Touch(t) => Some(PressEventData::Touch(t)),
325 _ => None,
326 });
327 if let Some(event) = event {
328 on_press.call(event);
329 }
330 }
331 })
332 .on_key_down(move |e: Event<KeyboardEventData>| {
333 if e.is_press_event() {
334 on_press.call(e.map(PressEventData::Keyboard))
335 }
336 })
337 }
338
339 fn on_secondary_down(
343 self,
344 on_secondary_down: impl Into<EventHandler<Event<PressEventData>>>,
345 ) -> Self {
346 let on_secondary_down = on_secondary_down.into();
347 self.on_pointer_down(move |e: Event<PointerEventData>| {
348 let event = e.try_map(|d| match d {
349 PointerEventData::Mouse(m) if m.button == Some(MouseButton::Right) => {
350 Some(PressEventData::Mouse(m))
351 }
352 _ => None,
353 });
354 if let Some(event) = event {
355 on_secondary_down.call(event);
356 }
357 })
358 }
359
360 fn on_all_press(self, on_press: impl Into<EventHandler<Event<PressEventData>>>) -> Self {
365 let on_press = on_press.into();
366 self.on_pointer_press({
367 let on_press = on_press.clone();
368 move |e: Event<PointerEventData>| {
369 let event = e.map(|d| match d {
370 PointerEventData::Mouse(m) => PressEventData::Mouse(m),
371 PointerEventData::Touch(t) => PressEventData::Touch(t),
372 });
373 on_press.call(event);
374 }
375 })
376 .on_key_down(move |e: Event<KeyboardEventData>| {
377 if e.is_press_event() {
378 on_press.call(e.map(PressEventData::Keyboard))
379 }
380 })
381 }
382 fn on_focus_press(
388 self,
389 on_focus_press: impl Into<EventHandler<Event<FocusPressEventData>>>,
390 ) -> Self {
391 let on_focus_press = on_focus_press.into();
392 if cfg!(target_os = "android") {
393 self.on_pointer_press(move |e: Event<PointerEventData>| {
394 let event = e.try_map(|d| match d {
395 PointerEventData::Mouse(m) if m.button == Some(MouseButton::Left) => {
396 Some(FocusPressEventData::Mouse(m))
397 }
398 PointerEventData::Touch(t) => Some(FocusPressEventData::Touch(t)),
399 _ => None,
400 });
401 if let Some(event) = event {
402 on_focus_press.call(event);
403 }
404 })
405 } else {
406 self.on_pointer_down(move |e: Event<PointerEventData>| {
407 let event = e.try_map(|d| match d {
408 PointerEventData::Mouse(m) if m.button == Some(MouseButton::Left) => {
409 Some(FocusPressEventData::Mouse(m))
410 }
411 PointerEventData::Touch(t) => Some(FocusPressEventData::Touch(t)),
412 _ => None,
413 });
414 if let Some(event) = event {
415 on_focus_press.call(event);
416 }
417 })
418 }
419 }
420}
421
422#[derive(Debug, Clone, PartialEq)]
424pub enum FocusPressEventData {
425 Mouse(MouseEventData),
426 Touch(TouchEventData),
427}
428
429impl FocusPressEventData {
430 pub fn global_location(&self) -> CursorPoint {
431 match self {
432 Self::Mouse(m) => m.global_location,
433 Self::Touch(t) => t.global_location,
434 }
435 }
436
437 pub fn element_location(&self) -> CursorPoint {
438 match self {
439 Self::Mouse(m) => m.element_location,
440 Self::Touch(t) => t.element_location,
441 }
442 }
443
444 pub fn button(&self) -> Option<MouseButton> {
445 match self {
446 Self::Mouse(m) => m.button,
447 Self::Touch(_) => None,
448 }
449 }
450}
451
452#[derive(Debug, Clone, PartialEq)]
454pub enum PressEventData {
455 Mouse(MouseEventData),
456 Keyboard(KeyboardEventData),
457 Touch(TouchEventData),
458}
459
460pub trait ContainerWithContentExt
462where
463 Self: LayoutExt,
464{
465 fn direction(mut self, direction: Direction) -> Self {
467 self.get_layout().layout.direction = direction;
468 self
469 }
470 fn main_align(mut self, main_align: Alignment) -> Self {
472 self.get_layout().layout.main_alignment = main_align;
473 self
474 }
475
476 fn cross_align(mut self, cross_align: Alignment) -> Self {
478 self.get_layout().layout.cross_alignment = cross_align;
479 self
480 }
481
482 fn spacing(mut self, spacing: impl Into<f32>) -> Self {
484 self.get_layout().layout.spacing = Length::new(spacing.into());
485 self
486 }
487
488 fn content(mut self, content: Content) -> Self {
490 self.get_layout().layout.content = content;
491 self
492 }
493 fn center(mut self) -> Self {
495 self.get_layout().layout.main_alignment = Alignment::Center;
496 self.get_layout().layout.cross_alignment = Alignment::Center;
497
498 self
499 }
500
501 fn offset_x(mut self, offset_x: impl Into<f32>) -> Self {
503 self.get_layout().layout.offset_x = Length::new(offset_x.into());
504 self
505 }
506
507 fn offset_y(mut self, offset_y: impl Into<f32>) -> Self {
509 self.get_layout().layout.offset_y = Length::new(offset_y.into());
510 self
511 }
512
513 fn vertical(mut self) -> Self {
515 self.get_layout().layout.direction = Direction::vertical();
516 self
517 }
518
519 fn horizontal(mut self) -> Self {
521 self.get_layout().layout.direction = Direction::horizontal();
522 self
523 }
524}
525
526pub trait ContainerSizeExt
528where
529 Self: LayoutExt,
530{
531 fn width(mut self, width: impl Into<Size>) -> Self {
533 self.get_layout().layout.width = width.into();
534 self
535 }
536
537 fn height(mut self, height: impl Into<Size>) -> Self {
539 self.get_layout().layout.height = height.into();
540 self
541 }
542
543 fn expanded(mut self) -> Self {
545 self.get_layout().layout.width = Size::fill();
546 self.get_layout().layout.height = Size::fill();
547 self
548 }
549}
550
551impl<T: ContainerExt> ContainerSizeExt for T {}
552
553pub trait ContainerPositionExt
555where
556 Self: LayoutExt,
557{
558 fn position(mut self, position: impl Into<Position>) -> Self {
560 self.get_layout().layout.position = position.into();
561 self
562 }
563}
564
565impl<T: ContainerExt> ContainerPositionExt for T {}
566
567pub trait ContainerExt
569where
570 Self: LayoutExt,
571{
572 fn padding(mut self, padding: impl Into<Gaps>) -> Self {
574 self.get_layout().layout.padding = padding.into();
575 self
576 }
577
578 fn margin(mut self, margin: impl Into<Gaps>) -> Self {
580 self.get_layout().layout.margin = margin.into();
581 self
582 }
583
584 fn min_width(mut self, minimum_width: impl Into<Size>) -> Self {
586 self.get_layout().layout.minimum_width = minimum_width.into();
587 self
588 }
589
590 fn min_height(mut self, minimum_height: impl Into<Size>) -> Self {
592 self.get_layout().layout.minimum_height = minimum_height.into();
593 self
594 }
595
596 fn max_width(mut self, maximum_width: impl Into<Size>) -> Self {
598 self.get_layout().layout.maximum_width = maximum_width.into();
599 self
600 }
601
602 fn max_height(mut self, maximum_height: impl Into<Size>) -> Self {
604 self.get_layout().layout.maximum_height = maximum_height.into();
605 self
606 }
607
608 fn visible_width(mut self, visible_width: impl Into<VisibleSize>) -> Self {
610 self.get_layout().layout.visible_width = visible_width.into();
611 self
612 }
613
614 fn visible_height(mut self, visible_height: impl Into<VisibleSize>) -> Self {
616 self.get_layout().layout.visible_height = visible_height.into();
617 self
618 }
619}
620
621pub trait LayoutExt
623where
624 Self: Sized,
625{
626 fn get_layout(&mut self) -> &mut LayoutData;
628
629 fn layout(mut self, layout: LayoutData) -> Self {
631 *self.get_layout() = layout;
632 self
633 }
634}
635
636pub trait ImageExt
638where
639 Self: LayoutExt,
640{
641 fn get_image_data(&mut self) -> &mut ImageData;
643
644 fn image_data(mut self, image_data: ImageData) -> Self {
646 *self.get_image_data() = image_data;
647 self
648 }
649
650 fn sampling_mode(mut self, sampling_mode: SamplingMode) -> Self {
652 self.get_image_data().sampling_mode = sampling_mode;
653 self
654 }
655
656 fn aspect_ratio(mut self, aspect_ratio: AspectRatio) -> Self {
658 self.get_image_data().aspect_ratio = aspect_ratio;
659 self
660 }
661
662 fn image_cover(mut self, image_cover: ImageCover) -> Self {
664 self.get_image_data().image_cover = image_cover;
665 self
666 }
667}
668
669pub trait AccessibilityExt: Sized {
671 fn get_accessibility_data(&mut self) -> &mut AccessibilityData;
673
674 fn accessibility(mut self, accessibility: AccessibilityData) -> Self {
676 *self.get_accessibility_data() = accessibility;
677 self
678 }
679
680 fn a11y_id(mut self, a11y_id: impl Into<Option<AccessibilityId>>) -> Self {
682 self.get_accessibility_data().a11y_id = a11y_id.into();
683 self
684 }
685
686 fn a11y_focusable(mut self, a11y_focusable: impl Into<Focusable>) -> Self {
688 self.get_accessibility_data().a11y_focusable = a11y_focusable.into();
689 self
690 }
691
692 fn a11y_auto_focus(mut self, a11y_auto_focus: impl Into<bool>) -> Self {
694 self.get_accessibility_data().a11y_auto_focus = a11y_auto_focus.into();
695 self
696 }
697
698 fn a11y_member_of(mut self, a11y_member_of: impl Into<AccessibilityId>) -> Self {
700 self.get_accessibility_data()
701 .builder
702 .set_member_of(a11y_member_of.into());
703 self
704 }
705
706 fn a11y_role(mut self, a11y_role: impl Into<AccessibilityRole>) -> Self {
708 self.get_accessibility_data()
709 .builder
710 .set_role(a11y_role.into());
711 self
712 }
713
714 fn a11y_alt(mut self, value: impl Into<Box<str>>) -> Self {
716 self.get_accessibility_data().builder.set_label(value);
717 self
718 }
719
720 fn a11y_builder(mut self, with: impl FnOnce(&mut accesskit::Node)) -> Self {
722 with(&mut self.get_accessibility_data().builder);
723 self
724 }
725}
726
727pub trait TextStyleExt
729where
730 Self: Sized,
731{
732 fn get_text_style_data(&mut self) -> &mut TextStyleData;
734
735 fn text_style(mut self, data: TextStyleData) -> Self {
737 *self.get_text_style_data() = data;
738 self
739 }
740
741 fn color(mut self, color: impl Into<Fill>) -> Self {
743 self.get_text_style_data().color = Some(color.into());
744 self
745 }
746
747 fn text_align(mut self, text_align: impl Into<TextAlign>) -> Self {
749 self.get_text_style_data().text_align = Some(text_align.into());
750 self
751 }
752
753 fn font_size(mut self, font_size: impl Into<FontSize>) -> Self {
755 self.get_text_style_data().font_size = Some(font_size.into());
756 self
757 }
758
759 fn font_family(mut self, font_family: impl Into<Cow<'static, str>>) -> Self {
761 self.get_text_style_data()
762 .font_families
763 .push(font_family.into());
764 self
765 }
766
767 fn font_slant(mut self, font_slant: impl Into<FontSlant>) -> Self {
769 self.get_text_style_data().font_slant = Some(font_slant.into());
770 self
771 }
772
773 fn font_weight(mut self, font_weight: impl Into<FontWeight>) -> Self {
775 self.get_text_style_data().font_weight = Some(font_weight.into());
776 self
777 }
778
779 fn font_width(mut self, font_width: impl Into<FontWidth>) -> Self {
781 self.get_text_style_data().font_width = Some(font_width.into());
782 self
783 }
784
785 fn text_height(mut self, text_height: impl Into<TextHeightBehavior>) -> Self {
787 self.get_text_style_data().text_height = Some(text_height.into());
788 self
789 }
790
791 fn text_overflow(mut self, text_overflow: impl Into<TextOverflow>) -> Self {
793 self.get_text_style_data().text_overflow = Some(text_overflow.into());
794 self
795 }
796
797 fn text_shadow(mut self, text_shadow: impl Into<TextShadow>) -> Self {
799 self.get_text_style_data()
800 .text_shadows
801 .push(text_shadow.into());
802 self
803 }
804
805 fn text_decoration(mut self, text_decoration: impl Into<TextDecoration>) -> Self {
807 self.get_text_style_data().text_decoration = Some(text_decoration.into());
808 self
809 }
810}
811
812pub trait StyleExt
814where
815 Self: Sized,
816{
817 fn get_style(&mut self) -> &mut StyleState;
819
820 fn background(mut self, background: impl Into<Fill>) -> Self {
822 self.get_style().background = background.into();
823 self
824 }
825
826 fn border(mut self, border: impl Into<Option<Border>>) -> Self {
828 if let Some(border) = border.into() {
829 self.get_style().borders.push(border);
830 }
831 self
832 }
833
834 fn shadow(mut self, shadow: impl Into<Shadow>) -> Self {
836 self.get_style().shadows.push(shadow.into());
837 self
838 }
839
840 fn corner_radius(mut self, corner_radius: impl Into<CornerRadius>) -> Self {
842 self.get_style().corner_radius = corner_radius.into();
843 self
844 }
845}
846
847impl<T: StyleExt> CornerRadiusExt for T {
848 fn with_corner_radius(mut self, corner_radius: f32) -> Self {
849 self.get_style().corner_radius = CornerRadius::new_all(corner_radius);
850 self
851 }
852}
853
854pub trait CornerRadiusExt: Sized {
856 fn with_corner_radius(self, corner_radius: f32) -> Self;
858
859 fn rounded_none(self) -> Self {
861 self.with_corner_radius(0.)
862 }
863
864 fn rounded(self) -> Self {
866 self.with_corner_radius(6.)
867 }
868
869 fn rounded_sm(self) -> Self {
871 self.with_corner_radius(4.)
872 }
873
874 fn rounded_md(self) -> Self {
876 self.with_corner_radius(6.)
877 }
878
879 fn rounded_lg(self) -> Self {
881 self.with_corner_radius(8.)
882 }
883
884 fn rounded_xl(self) -> Self {
886 self.with_corner_radius(12.)
887 }
888
889 fn rounded_2xl(self) -> Self {
891 self.with_corner_radius(16.)
892 }
893
894 fn rounded_3xl(self) -> Self {
896 self.with_corner_radius(24.)
897 }
898
899 fn rounded_4xl(self) -> Self {
901 self.with_corner_radius(32.)
902 }
903
904 fn rounded_full(self) -> Self {
906 self.with_corner_radius(99.)
907 }
908}
909
910pub trait MaybeExt
912where
913 Self: Sized,
914{
915 fn maybe(self, bool: impl Into<bool>, then: impl FnOnce(Self) -> Self) -> Self {
917 if bool.into() { then(self) } else { self }
918 }
919
920 fn map<T>(self, data: Option<T>, then: impl FnOnce(Self, T) -> Self) -> Self {
922 if let Some(data) = data {
923 then(self, data)
924 } else {
925 self
926 }
927 }
928}
929
930pub trait LayerExt
932where
933 Self: Sized,
934{
935 fn get_layer(&mut self) -> &mut Layer;
937
938 fn layer(mut self, layer: impl Into<Layer>) -> Self {
940 *self.get_layer() = layer.into();
941 self
942 }
943}
944
945pub trait ScrollableExt
946where
947 Self: Sized,
948{
949 fn get_effect(&mut self) -> &mut EffectData;
951
952 fn scrollable(mut self, scrollable: impl Into<bool>) -> Self {
955 self.get_effect().scrollable = scrollable.into();
956 self
957 }
958}
959
960pub trait InteractiveExt
962where
963 Self: Sized,
964{
965 fn get_effect(&mut self) -> &mut EffectData;
967
968 fn interactive(mut self, interactive: impl Into<Interactive>) -> Self {
970 self.get_effect().interactive = interactive.into();
971 self
972 }
973}
974
975pub trait EffectExt: Sized {
977 fn get_effect(&mut self) -> &mut EffectData;
979
980 fn effect(mut self, effect: EffectData) -> Self {
982 *self.get_effect() = effect;
983 self
984 }
985
986 fn overflow(mut self, overflow: impl Into<Overflow>) -> Self {
988 self.get_effect().overflow = overflow.into();
989 self
990 }
991
992 fn blur(mut self, blur: impl Into<f32>) -> Self {
994 self.get_effect().blur = Some(blur.into());
995 self
996 }
997
998 fn rotation(mut self, rotation: impl Into<f32>) -> Self {
1000 self.get_effect().rotation = Some(rotation.into());
1001 self
1002 }
1003
1004 fn opacity(mut self, opacity: impl Into<f32>) -> Self {
1006 self.get_effect().opacity = Some(opacity.into());
1007 self
1008 }
1009
1010 fn scale(mut self, scale: impl Into<Scale>) -> Self {
1012 self.get_effect().scale = Some(scale.into());
1013 self
1014 }
1015
1016 fn transform_origin(mut self, transform_origin: impl Into<TransformOrigin>) -> Self {
1020 self.get_effect().transform_origin = transform_origin.into();
1021 self
1022 }
1023}