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 VisibleEventData,
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 {
131 let mut hasher = FxHasher::default();
132 key.hash(&mut hasher);
133 *self.write_key() = DiffKey::U64(hasher.finish());
134 self
135 }
136}
137
138pub trait ListExt {
140 fn with(self, other: Self) -> Self;
142}
143
144impl<T> ListExt for Vec<T> {
145 fn with(mut self, other: Self) -> Self {
146 self.extend(other);
147 self
148 }
149}
150
151macro_rules! event_handlers {
152 (
153 $handler_variant:ident, $event_data:ty;
154 $(
155 $(#[$attr:meta])*
156 $name:ident => $event_variant:expr ;
157 )*
158 ) => {
159 paste! {
160 $(
161 $(#[$attr])*
162 fn [<on_$name>](mut self, [<on_$name>]: impl Into<EventHandler<Event<$event_data>>>) -> Self {
163 self.get_event_handlers()
164 .insert($event_variant, EventHandlerType::$handler_variant([<on_$name>].into()));
165 self
166 }
167 )*
168 }
169 };
170}
171
172pub trait EventHandlersExt: Sized {
180 fn get_event_handlers(&mut self) -> &mut FxHashMap<EventName, EventHandlerType>;
182
183 fn with_event_handlers(
185 mut self,
186 event_handlers: FxHashMap<EventName, EventHandlerType>,
187 ) -> Self {
188 *self.get_event_handlers() = event_handlers;
189 self
190 }
191
192 event_handlers! {
193 Mouse,
194 MouseEventData;
195
196 mouse_down => EventName::MouseDown;
198 mouse_up => EventName::MouseUp;
200 mouse_move => EventName::MouseMove;
202
203 }
204
205 event_handlers! {
206 Pointer,
207 PointerEventData;
208
209 global_pointer_press => EventName::GlobalPointerPress;
211 global_pointer_down => EventName::GlobalPointerDown;
213 global_pointer_move => EventName::GlobalPointerMove;
215
216 capture_global_pointer_move => EventName::CaptureGlobalPointerMove;
218 capture_global_pointer_press => EventName::CaptureGlobalPointerPress;
220 }
221
222 event_handlers! {
223 Keyboard,
224 KeyboardEventData;
225
226 key_down => EventName::KeyDown;
228 key_up => EventName::KeyUp;
230
231 global_key_down => EventName::GlobalKeyDown;
233 global_key_up => EventName::GlobalKeyUp;
235 }
236
237 event_handlers! {
238 Wheel,
239 WheelEventData;
240
241 wheel => EventName::Wheel;
243 }
244
245 event_handlers! {
246 Touch,
247 TouchEventData;
248
249 touch_cancel => EventName::TouchCancel;
251 touch_start => EventName::TouchStart;
253 touch_move => EventName::TouchMove;
255 touch_end => EventName::TouchEnd;
257 }
258
259 event_handlers! {
260 Pointer,
261 PointerEventData;
262
263 pointer_press => EventName::PointerPress;
265 pointer_down => EventName::PointerDown;
267 pointer_move => EventName::PointerMove;
269 pointer_enter => EventName::PointerEnter;
271 pointer_leave => EventName::PointerLeave;
273 pointer_over => EventName::PointerOver;
275 pointer_out => EventName::PointerOut;
277 }
278
279 event_handlers! {
280 File,
281 FileEventData;
282
283 file_drop => EventName::FileDrop;
285 global_file_hover => EventName::GlobalFileHover;
287 global_file_hover_cancelled => EventName::GlobalFileHoverCancelled;
289 }
290
291 event_handlers! {
292 ImePreedit,
293 ImePreeditEventData;
294
295 ime_preedit => EventName::ImePreedit;
297 }
298
299 fn on_sized(mut self, on_sized: impl Into<EventHandler<Event<SizedEventData>>>) -> Self
301 where
302 Self: LayoutExt,
303 {
304 self.get_event_handlers()
305 .insert(EventName::Sized, EventHandlerType::Sized(on_sized.into()));
306 self.get_layout().layout.has_layout_references = true;
307 self
308 }
309
310 fn on_visible(mut self, on_visible: impl Into<EventHandler<Event<VisibleEventData>>>) -> Self {
312 self.get_event_handlers().insert(
313 EventName::Visible,
314 EventHandlerType::Visible(on_visible.into()),
315 );
316 self
317 }
318
319 fn on_press(self, on_press: impl Into<EventHandler<Event<PressEventData>>>) -> Self {
326 let on_press = on_press.into();
327 self.on_pointer_press({
328 let on_press = on_press.clone();
329 move |e: Event<PointerEventData>| {
330 let event = e.try_map(|d| match d {
331 PointerEventData::Mouse(m) if m.button == Some(MouseButton::Left) => {
332 Some(PressEventData::Mouse(m))
333 }
334 PointerEventData::Touch(t) => Some(PressEventData::Touch(t)),
335 _ => None,
336 });
337 if let Some(event) = event {
338 on_press.call(event);
339 }
340 }
341 })
342 .on_key_down(move |e: Event<KeyboardEventData>| {
343 if e.is_press_event() {
344 on_press.call(e.map(PressEventData::Keyboard))
345 }
346 })
347 }
348
349 fn on_secondary_down(
353 self,
354 on_secondary_down: impl Into<EventHandler<Event<PressEventData>>>,
355 ) -> Self {
356 let on_secondary_down = on_secondary_down.into();
357 self.on_pointer_down(move |e: Event<PointerEventData>| {
358 let event = e.try_map(|d| match d {
359 PointerEventData::Mouse(m) if m.button == Some(MouseButton::Right) => {
360 Some(PressEventData::Mouse(m))
361 }
362 _ => None,
363 });
364 if let Some(event) = event {
365 on_secondary_down.call(event);
366 }
367 })
368 }
369
370 fn on_all_press(self, on_press: impl Into<EventHandler<Event<PressEventData>>>) -> Self {
375 let on_press = on_press.into();
376 self.on_pointer_press({
377 let on_press = on_press.clone();
378 move |e: Event<PointerEventData>| {
379 let event = e.map(|d| match d {
380 PointerEventData::Mouse(m) => PressEventData::Mouse(m),
381 PointerEventData::Touch(t) => PressEventData::Touch(t),
382 });
383 on_press.call(event);
384 }
385 })
386 .on_key_down(move |e: Event<KeyboardEventData>| {
387 if e.is_press_event() {
388 on_press.call(e.map(PressEventData::Keyboard))
389 }
390 })
391 }
392 fn on_focus_press(
398 self,
399 on_focus_press: impl Into<EventHandler<Event<FocusPressEventData>>>,
400 ) -> Self {
401 let on_focus_press = on_focus_press.into();
402 if cfg!(target_os = "android") {
403 self.on_pointer_press(move |e: Event<PointerEventData>| {
404 let event = e.try_map(|d| match d {
405 PointerEventData::Mouse(m) if m.button == Some(MouseButton::Left) => {
406 Some(FocusPressEventData::Mouse(m))
407 }
408 PointerEventData::Touch(t) => Some(FocusPressEventData::Touch(t)),
409 _ => None,
410 });
411 if let Some(event) = event {
412 on_focus_press.call(event);
413 }
414 })
415 } else {
416 self.on_pointer_down(move |e: Event<PointerEventData>| {
417 let event = e.try_map(|d| match d {
418 PointerEventData::Mouse(m) if m.button == Some(MouseButton::Left) => {
419 Some(FocusPressEventData::Mouse(m))
420 }
421 PointerEventData::Touch(t) => Some(FocusPressEventData::Touch(t)),
422 _ => None,
423 });
424 if let Some(event) = event {
425 on_focus_press.call(event);
426 }
427 })
428 }
429 }
430}
431
432#[derive(Debug, Clone, PartialEq)]
434pub enum FocusPressEventData {
435 Mouse(MouseEventData),
436 Touch(TouchEventData),
437}
438
439impl FocusPressEventData {
440 pub fn global_location(&self) -> CursorPoint {
441 match self {
442 Self::Mouse(m) => m.global_location,
443 Self::Touch(t) => t.global_location,
444 }
445 }
446
447 pub fn element_location(&self) -> CursorPoint {
448 match self {
449 Self::Mouse(m) => m.element_location,
450 Self::Touch(t) => t.element_location,
451 }
452 }
453
454 pub fn button(&self) -> Option<MouseButton> {
455 match self {
456 Self::Mouse(m) => m.button,
457 Self::Touch(_) => None,
458 }
459 }
460}
461
462#[derive(Debug, Clone, PartialEq)]
464pub enum PressEventData {
465 Mouse(MouseEventData),
466 Keyboard(KeyboardEventData),
467 Touch(TouchEventData),
468}
469
470pub trait ContainerWithContentExt
472where
473 Self: LayoutExt,
474{
475 fn direction(mut self, direction: Direction) -> Self {
477 self.get_layout().layout.direction = direction;
478 self
479 }
480 fn main_align(mut self, main_align: Alignment) -> Self {
482 self.get_layout().layout.main_alignment = main_align;
483 self
484 }
485
486 fn cross_align(mut self, cross_align: Alignment) -> Self {
488 self.get_layout().layout.cross_alignment = cross_align;
489 self
490 }
491
492 fn spacing(mut self, spacing: impl Into<f32>) -> Self {
494 self.get_layout().layout.spacing = Length::new(spacing.into());
495 self
496 }
497
498 fn content(mut self, content: Content) -> Self {
500 self.get_layout().layout.content = content;
501 self
502 }
503 fn center(mut self) -> Self {
505 self.get_layout().layout.main_alignment = Alignment::Center;
506 self.get_layout().layout.cross_alignment = Alignment::Center;
507
508 self
509 }
510
511 fn offset_x(mut self, offset_x: impl Into<f32>) -> Self {
513 self.get_layout().layout.offset_x = Length::new(offset_x.into());
514 self
515 }
516
517 fn offset_y(mut self, offset_y: impl Into<f32>) -> Self {
519 self.get_layout().layout.offset_y = Length::new(offset_y.into());
520 self
521 }
522
523 fn vertical(mut self) -> Self {
525 self.get_layout().layout.direction = Direction::vertical();
526 self
527 }
528
529 fn horizontal(mut self) -> Self {
531 self.get_layout().layout.direction = Direction::horizontal();
532 self
533 }
534}
535
536pub trait ContainerSizeExt
538where
539 Self: LayoutExt,
540{
541 fn width(mut self, width: impl Into<Size>) -> Self {
543 self.get_layout().layout.width = width.into();
544 self
545 }
546
547 fn height(mut self, height: impl Into<Size>) -> Self {
549 self.get_layout().layout.height = height.into();
550 self
551 }
552
553 fn expanded(mut self) -> Self {
555 self.get_layout().layout.width = Size::fill();
556 self.get_layout().layout.height = Size::fill();
557 self
558 }
559}
560
561impl<T: ContainerExt> ContainerSizeExt for T {}
562
563pub trait ContainerExt
565where
566 Self: LayoutExt,
567{
568 fn position(mut self, position: impl Into<Position>) -> Self {
570 self.get_layout().layout.position = position.into();
571 self
572 }
573
574 fn padding(mut self, padding: impl Into<Gaps>) -> Self {
576 self.get_layout().layout.padding = padding.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 fn min_width(mut self, minimum_width: impl Into<Size>) -> Self {
588 self.get_layout().layout.minimum_width = minimum_width.into();
589 self
590 }
591
592 fn min_height(mut self, minimum_height: impl Into<Size>) -> Self {
594 self.get_layout().layout.minimum_height = minimum_height.into();
595 self
596 }
597
598 fn max_width(mut self, maximum_width: impl Into<Size>) -> Self {
600 self.get_layout().layout.maximum_width = maximum_width.into();
601 self
602 }
603
604 fn max_height(mut self, maximum_height: impl Into<Size>) -> Self {
606 self.get_layout().layout.maximum_height = maximum_height.into();
607 self
608 }
609
610 fn visible_width(mut self, visible_width: impl Into<VisibleSize>) -> Self {
612 self.get_layout().layout.visible_width = visible_width.into();
613 self
614 }
615
616 fn visible_height(mut self, visible_height: impl Into<VisibleSize>) -> Self {
618 self.get_layout().layout.visible_height = visible_height.into();
619 self
620 }
621}
622
623pub trait LayoutExt
625where
626 Self: Sized,
627{
628 fn get_layout(&mut self) -> &mut LayoutData;
630
631 fn layout(mut self, layout: LayoutData) -> Self {
633 *self.get_layout() = layout;
634 self
635 }
636}
637
638pub trait ImageExt
640where
641 Self: LayoutExt,
642{
643 fn get_image_data(&mut self) -> &mut ImageData;
645
646 fn image_data(mut self, image_data: ImageData) -> Self {
648 *self.get_image_data() = image_data;
649 self
650 }
651
652 fn sampling_mode(mut self, sampling_mode: SamplingMode) -> Self {
654 self.get_image_data().sampling_mode = sampling_mode;
655 self
656 }
657
658 fn aspect_ratio(mut self, aspect_ratio: AspectRatio) -> Self {
660 self.get_image_data().aspect_ratio = aspect_ratio;
661 self
662 }
663
664 fn image_cover(mut self, image_cover: ImageCover) -> Self {
666 self.get_image_data().image_cover = image_cover;
667 self
668 }
669}
670
671pub trait AccessibilityExt: Sized {
673 fn get_accessibility_data(&mut self) -> &mut AccessibilityData;
675
676 fn accessibility(mut self, accessibility: AccessibilityData) -> Self {
678 *self.get_accessibility_data() = accessibility;
679 self
680 }
681
682 fn a11y_id(mut self, a11y_id: impl Into<Option<AccessibilityId>>) -> Self {
684 self.get_accessibility_data().a11y_id = a11y_id.into();
685 self
686 }
687
688 fn a11y_focusable(mut self, a11y_focusable: impl Into<Focusable>) -> Self {
690 self.get_accessibility_data().a11y_focusable = a11y_focusable.into();
691 self
692 }
693
694 fn a11y_auto_focus(mut self, a11y_auto_focus: impl Into<bool>) -> Self {
696 self.get_accessibility_data().a11y_auto_focus = a11y_auto_focus.into();
697 self
698 }
699
700 fn a11y_member_of(mut self, a11y_member_of: impl Into<AccessibilityId>) -> Self {
702 self.get_accessibility_data()
703 .builder
704 .set_member_of(a11y_member_of.into());
705 self
706 }
707
708 fn a11y_role(mut self, a11y_role: impl Into<AccessibilityRole>) -> Self {
710 self.get_accessibility_data()
711 .builder
712 .set_role(a11y_role.into());
713 self
714 }
715
716 fn a11y_alt(mut self, value: impl Into<Box<str>>) -> Self {
718 self.get_accessibility_data().builder.set_label(value);
719 self
720 }
721
722 fn a11y_builder(mut self, with: impl FnOnce(&mut accesskit::Node)) -> Self {
724 with(&mut self.get_accessibility_data().builder);
725 self
726 }
727}
728
729pub trait TextStyleExt
731where
732 Self: Sized,
733{
734 fn get_text_style_data(&mut self) -> &mut TextStyleData;
736
737 fn text_style(mut self, data: TextStyleData) -> Self {
739 *self.get_text_style_data() = data;
740 self
741 }
742
743 fn color(mut self, color: impl Into<Fill>) -> Self {
745 self.get_text_style_data().color = Some(color.into());
746 self
747 }
748
749 fn text_align(mut self, text_align: impl Into<TextAlign>) -> Self {
751 self.get_text_style_data().text_align = Some(text_align.into());
752 self
753 }
754
755 fn font_size(mut self, font_size: impl Into<FontSize>) -> Self {
757 self.get_text_style_data().font_size = Some(font_size.into());
758 self
759 }
760
761 fn font_family(mut self, font_family: impl Into<Cow<'static, str>>) -> Self {
763 self.get_text_style_data()
764 .font_families
765 .push(font_family.into());
766 self
767 }
768
769 fn font_slant(mut self, font_slant: impl Into<FontSlant>) -> Self {
771 self.get_text_style_data().font_slant = Some(font_slant.into());
772 self
773 }
774
775 fn font_weight(mut self, font_weight: impl Into<FontWeight>) -> Self {
777 self.get_text_style_data().font_weight = Some(font_weight.into());
778 self
779 }
780
781 fn font_width(mut self, font_width: impl Into<FontWidth>) -> Self {
783 self.get_text_style_data().font_width = Some(font_width.into());
784 self
785 }
786
787 fn text_height(mut self, text_height: impl Into<TextHeightBehavior>) -> Self {
789 self.get_text_style_data().text_height = Some(text_height.into());
790 self
791 }
792
793 fn text_overflow(mut self, text_overflow: impl Into<TextOverflow>) -> Self {
795 self.get_text_style_data().text_overflow = Some(text_overflow.into());
796 self
797 }
798
799 fn text_shadow(mut self, text_shadow: impl Into<TextShadow>) -> Self {
801 self.get_text_style_data()
802 .text_shadows
803 .push(text_shadow.into());
804 self
805 }
806
807 fn text_decoration(mut self, text_decoration: impl Into<TextDecoration>) -> Self {
809 self.get_text_style_data().text_decoration = Some(text_decoration.into());
810 self
811 }
812}
813
814pub trait StyleExt
816where
817 Self: Sized,
818{
819 fn get_style(&mut self) -> &mut StyleState;
821
822 fn background(mut self, background: impl Into<Fill>) -> Self {
824 self.get_style().background = background.into();
825 self
826 }
827
828 fn border(mut self, border: impl Into<Option<Border>>) -> Self {
830 if let Some(border) = border.into() {
831 self.get_style().borders.push(border);
832 }
833 self
834 }
835
836 fn shadow(mut self, shadow: impl Into<Shadow>) -> Self {
838 self.get_style().shadows.push(shadow.into());
839 self
840 }
841
842 fn corner_radius(mut self, corner_radius: impl Into<CornerRadius>) -> Self {
844 self.get_style().corner_radius = corner_radius.into();
845 self
846 }
847}
848
849impl<T: StyleExt> CornerRadiusExt for T {
850 fn with_corner_radius(mut self, corner_radius: f32) -> Self {
851 self.get_style().corner_radius = CornerRadius::new_all(corner_radius);
852 self
853 }
854}
855
856pub trait CornerRadiusExt: Sized {
858 fn with_corner_radius(self, corner_radius: f32) -> Self;
860
861 fn rounded_none(self) -> Self {
863 self.with_corner_radius(0.)
864 }
865
866 fn rounded(self) -> Self {
868 self.with_corner_radius(6.)
869 }
870
871 fn rounded_sm(self) -> Self {
873 self.with_corner_radius(4.)
874 }
875
876 fn rounded_md(self) -> Self {
878 self.with_corner_radius(6.)
879 }
880
881 fn rounded_lg(self) -> Self {
883 self.with_corner_radius(8.)
884 }
885
886 fn rounded_xl(self) -> Self {
888 self.with_corner_radius(12.)
889 }
890
891 fn rounded_2xl(self) -> Self {
893 self.with_corner_radius(16.)
894 }
895
896 fn rounded_3xl(self) -> Self {
898 self.with_corner_radius(24.)
899 }
900
901 fn rounded_4xl(self) -> Self {
903 self.with_corner_radius(32.)
904 }
905
906 fn rounded_full(self) -> Self {
908 self.with_corner_radius(99.)
909 }
910}
911
912pub trait MaybeExt
914where
915 Self: Sized,
916{
917 fn maybe(self, bool: impl Into<bool>, then: impl FnOnce(Self) -> Self) -> Self {
919 if bool.into() { then(self) } else { self }
920 }
921
922 fn map<T>(self, data: Option<T>, then: impl FnOnce(Self, T) -> Self) -> Self {
924 if let Some(data) = data {
925 then(self, data)
926 } else {
927 self
928 }
929 }
930}
931
932pub trait LayerExt
934where
935 Self: Sized,
936{
937 fn get_layer(&mut self) -> &mut Layer;
939
940 fn layer(mut self, layer: impl Into<Layer>) -> Self {
942 *self.get_layer() = layer.into();
943 self
944 }
945}
946
947pub trait ScrollableExt
948where
949 Self: Sized,
950{
951 fn get_effect(&mut self) -> &mut EffectData;
953
954 fn scrollable(mut self, scrollable: impl Into<bool>) -> Self {
957 self.get_effect().scrollable = scrollable.into();
958 self
959 }
960}
961
962pub trait InteractiveExt
964where
965 Self: Sized,
966{
967 fn get_effect(&mut self) -> &mut EffectData;
969
970 fn interactive(mut self, interactive: impl Into<Interactive>) -> Self {
972 self.get_effect().interactive = interactive.into();
973 self
974 }
975}
976
977pub trait EffectExt: Sized {
979 fn get_effect(&mut self) -> &mut EffectData;
981
982 fn effect(mut self, effect: EffectData) -> Self {
984 *self.get_effect() = effect;
985 self
986 }
987
988 fn overflow(mut self, overflow: impl Into<Overflow>) -> Self {
990 self.get_effect().overflow = overflow.into();
991 self
992 }
993
994 fn blur(mut self, blur: impl Into<f32>) -> Self {
996 self.get_effect().blur = Some(blur.into());
997 self
998 }
999
1000 fn rotation(mut self, rotation: impl Into<f32>) -> Self {
1002 self.get_effect().rotation = Some(rotation.into());
1003 self
1004 }
1005
1006 fn opacity(mut self, opacity: impl Into<f32>) -> Self {
1008 self.get_effect().opacity = Some(opacity.into());
1009 self
1010 }
1011
1012 fn scale(mut self, scale: impl Into<Scale>) -> Self {
1014 self.get_effect().scale = Some(scale.into());
1015 self
1016 }
1017
1018 fn transform_origin(mut self, transform_origin: impl Into<TransformOrigin>) -> Self {
1022 self.get_effect().transform_origin = transform_origin.into();
1023 self
1024 }
1025}