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