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(move |e: Event<KeyboardEventData>| {
285 if Focus::is_pressed(&e) {
286 on_press.call(e.map(PressEventData::Keyboard))
287 }
288 })
289 }
290
291 fn on_secondary_press(
295 self,
296 on_pointer_press: impl Into<EventHandler<Event<PressEventData>>>,
297 ) -> Self {
298 let on_pointer_press = on_pointer_press.into();
299 self.on_pointer_press(move |e: Event<PointerEventData>| {
300 let event = e.try_map(|d| match d {
301 PointerEventData::Mouse(m) if m.button == Some(MouseButton::Right) => {
302 Some(PressEventData::Mouse(m))
303 }
304 _ => None,
305 });
306 if let Some(event) = event {
307 on_pointer_press.call(event);
308 }
309 })
310 }
311
312 fn on_all_press(self, on_press: impl Into<EventHandler<Event<PressEventData>>>) -> Self {
317 let on_press = on_press.into();
318 self.on_pointer_press({
319 let on_press = on_press.clone();
320 move |e: Event<PointerEventData>| {
321 let event = e.try_map(|d| match d {
322 PointerEventData::Mouse(m) => Some(PressEventData::Mouse(m)),
323 PointerEventData::Touch(t) => Some(PressEventData::Touch(t)),
324 });
325 if let Some(event) = event {
326 on_press.call(event);
327 }
328 }
329 })
330 .on_key_down(move |e: Event<KeyboardEventData>| {
331 if Focus::is_pressed(&e) {
332 on_press.call(e.map(PressEventData::Keyboard))
333 }
334 })
335 }
336}
337
338#[derive(Debug, Clone, PartialEq)]
339pub enum PressEventData {
340 Mouse(MouseEventData),
341 Keyboard(KeyboardEventData),
342 Touch(TouchEventData),
343}
344
345pub trait ContainerWithContentExt
346where
347 Self: LayoutExt,
348{
349 fn direction(mut self, direction: Direction) -> Self {
350 self.get_layout().layout.direction = direction;
351 self
352 }
353 fn main_align(mut self, main_align: Alignment) -> Self {
354 self.get_layout().layout.main_alignment = main_align;
355 self
356 }
357
358 fn cross_align(mut self, cross_align: Alignment) -> Self {
359 self.get_layout().layout.cross_alignment = cross_align;
360 self
361 }
362
363 fn spacing(mut self, spacing: impl Into<f32>) -> Self {
364 self.get_layout().layout.spacing = Length::new(spacing.into());
365 self
366 }
367
368 fn content(mut self, content: Content) -> Self {
369 self.get_layout().layout.content = content;
370 self
371 }
372 fn center(mut self) -> Self {
373 self.get_layout().layout.main_alignment = Alignment::Center;
374 self.get_layout().layout.cross_alignment = Alignment::Center;
375
376 self
377 }
378
379 fn offset_x(mut self, offset_x: impl Into<f32>) -> Self {
380 self.get_layout().layout.offset_x = Length::new(offset_x.into());
381 self
382 }
383
384 fn offset_y(mut self, offset_y: impl Into<f32>) -> Self {
385 self.get_layout().layout.offset_y = Length::new(offset_y.into());
386 self
387 }
388
389 fn vertical(mut self) -> Self {
390 self.get_layout().layout.direction = Direction::vertical();
391 self
392 }
393
394 fn horizontal(mut self) -> Self {
395 self.get_layout().layout.direction = Direction::horizontal();
396 self
397 }
398}
399
400pub trait ContainerSizeExt
401where
402 Self: LayoutExt,
403{
404 fn width(mut self, width: impl Into<Size>) -> Self {
405 self.get_layout().layout.width = width.into();
406 self
407 }
408
409 fn height(mut self, height: impl Into<Size>) -> Self {
410 self.get_layout().layout.height = height.into();
411 self
412 }
413
414 fn expanded(mut self) -> Self {
416 self.get_layout().layout.width = Size::fill();
417 self.get_layout().layout.height = Size::fill();
418 self
419 }
420}
421
422impl<T: ContainerExt> ContainerSizeExt for T {}
423
424pub trait ContainerExt
425where
426 Self: LayoutExt,
427{
428 fn position(mut self, position: impl Into<Position>) -> Self {
429 self.get_layout().layout.position = position.into();
430 self
431 }
432
433 fn padding(mut self, padding: impl Into<Gaps>) -> Self {
434 self.get_layout().layout.padding = padding.into();
435 self
436 }
437
438 fn margin(mut self, margin: impl Into<Gaps>) -> Self {
439 self.get_layout().layout.margin = margin.into();
440 self
441 }
442
443 fn min_width(mut self, minimum_width: impl Into<Size>) -> Self {
444 self.get_layout().layout.minimum_width = minimum_width.into();
445 self
446 }
447
448 fn min_height(mut self, minimum_height: impl Into<Size>) -> Self {
449 self.get_layout().layout.minimum_height = minimum_height.into();
450 self
451 }
452
453 fn max_width(mut self, maximum_width: impl Into<Size>) -> Self {
454 self.get_layout().layout.maximum_width = maximum_width.into();
455 self
456 }
457
458 fn max_height(mut self, maximum_height: impl Into<Size>) -> Self {
459 self.get_layout().layout.maximum_height = maximum_height.into();
460 self
461 }
462
463 fn visible_width(mut self, visible_width: impl Into<VisibleSize>) -> Self {
464 self.get_layout().layout.visible_width = visible_width.into();
465 self
466 }
467
468 fn visible_height(mut self, visible_height: impl Into<VisibleSize>) -> Self {
469 self.get_layout().layout.visible_height = visible_height.into();
470 self
471 }
472}
473
474pub trait LayoutExt
475where
476 Self: Sized,
477{
478 fn get_layout(&mut self) -> &mut LayoutData;
479
480 fn layout(mut self, layout: LayoutData) -> Self {
481 *self.get_layout() = layout;
482 self
483 }
484}
485
486pub trait ImageExt
487where
488 Self: LayoutExt,
489{
490 fn get_image_data(&mut self) -> &mut ImageData;
491
492 fn image_data(mut self, image_data: ImageData) -> Self {
493 *self.get_image_data() = image_data;
494 self
495 }
496
497 fn sampling_mode(mut self, sampling_mode: SamplingMode) -> Self {
498 self.get_image_data().sampling_mode = sampling_mode;
499 self
500 }
501
502 fn aspect_ratio(mut self, aspect_ratio: AspectRatio) -> Self {
503 self.get_image_data().aspect_ratio = aspect_ratio;
504 self
505 }
506
507 fn image_cover(mut self, image_cover: ImageCover) -> Self {
508 self.get_image_data().image_cover = image_cover;
509 self
510 }
511}
512
513pub trait AccessibilityExt: Sized {
514 fn get_accessibility_data(&mut self) -> &mut AccessibilityData;
515
516 fn accessibility(mut self, accessibility: AccessibilityData) -> Self {
517 *self.get_accessibility_data() = accessibility;
518 self
519 }
520
521 fn a11y_id(mut self, a11y_id: impl Into<Option<AccessibilityId>>) -> Self {
522 self.get_accessibility_data().a11y_id = a11y_id.into();
523 self
524 }
525
526 fn a11y_focusable(mut self, a11y_focusable: impl Into<Focusable>) -> Self {
527 self.get_accessibility_data().a11y_focusable = a11y_focusable.into();
528 self
529 }
530
531 fn a11y_auto_focus(mut self, a11y_auto_focus: impl Into<bool>) -> Self {
532 self.get_accessibility_data().a11y_auto_focus = a11y_auto_focus.into();
533 self
534 }
535
536 fn a11y_member_of(mut self, a11y_member_of: impl Into<AccessibilityId>) -> Self {
537 self.get_accessibility_data()
538 .builder
539 .set_member_of(a11y_member_of.into());
540 self
541 }
542
543 fn a11y_role(mut self, a11y_role: impl Into<AccessibilityRole>) -> Self {
544 self.get_accessibility_data()
545 .builder
546 .set_role(a11y_role.into());
547 self
548 }
549
550 fn a11y_alt(mut self, value: impl Into<Box<str>>) -> Self {
551 self.get_accessibility_data().builder.set_label(value);
552 self
553 }
554
555 fn a11y_builder(mut self, with: impl FnOnce(&mut accesskit::Node)) -> Self {
556 with(&mut self.get_accessibility_data().builder);
557 self
558 }
559}
560
561pub trait TextStyleExt
562where
563 Self: Sized,
564{
565 fn get_text_style_data(&mut self) -> &mut TextStyleData;
566
567 fn text_style(mut self, data: TextStyleData) -> Self {
568 *self.get_text_style_data() = data;
569 self
570 }
571
572 fn color(mut self, color: impl Into<Color>) -> Self {
573 self.get_text_style_data().color = Some(color.into());
574 self
575 }
576
577 fn text_align(mut self, text_align: impl Into<TextAlign>) -> Self {
578 self.get_text_style_data().text_align = Some(text_align.into());
579 self
580 }
581
582 fn font_size(mut self, font_size: impl Into<FontSize>) -> Self {
583 self.get_text_style_data().font_size = Some(font_size.into());
584 self
585 }
586
587 fn font_family(mut self, font_family: impl Into<Cow<'static, str>>) -> Self {
588 self.get_text_style_data()
589 .font_families
590 .push(font_family.into());
591 self
592 }
593
594 fn font_slant(mut self, font_slant: impl Into<FontSlant>) -> Self {
595 self.get_text_style_data().font_slant = Some(font_slant.into());
596 self
597 }
598
599 fn font_weight(mut self, font_weight: impl Into<FontWeight>) -> Self {
600 self.get_text_style_data().font_weight = Some(font_weight.into());
601 self
602 }
603
604 fn font_width(mut self, font_width: impl Into<FontWidth>) -> Self {
605 self.get_text_style_data().font_width = Some(font_width.into());
606 self
607 }
608
609 fn text_height(mut self, text_height: impl Into<TextHeightBehavior>) -> Self {
610 self.get_text_style_data().text_height = Some(text_height.into());
611 self
612 }
613
614 fn text_overflow(mut self, text_overflow: impl Into<TextOverflow>) -> Self {
615 self.get_text_style_data().text_overflow = Some(text_overflow.into());
616 self
617 }
618
619 fn text_shadow(mut self, text_shadow: impl Into<TextShadow>) -> Self {
620 self.get_text_style_data()
621 .text_shadows
622 .push(text_shadow.into());
623 self
624 }
625
626 fn text_decoration(mut self, text_decoration: impl Into<TextDecoration>) -> Self {
627 self.get_text_style_data().text_decoration = Some(text_decoration.into());
628 self
629 }
630}
631
632pub trait StyleExt
633where
634 Self: Sized,
635{
636 fn get_style(&mut self) -> &mut StyleState;
637
638 fn background<S: Into<Color>>(mut self, background: S) -> Self {
639 self.get_style().background = Fill::Color(background.into());
640 self
641 }
642
643 fn background_conic_gradient<S: Into<ConicGradient>>(mut self, background: S) -> Self {
644 self.get_style().background = Fill::ConicGradient(Box::new(background.into()));
645 self
646 }
647
648 fn background_linear_gradient<S: Into<LinearGradient>>(mut self, background: S) -> Self {
649 self.get_style().background = Fill::LinearGradient(Box::new(background.into()));
650 self
651 }
652
653 fn background_radial_gradient<S: Into<RadialGradient>>(mut self, background: S) -> Self {
654 self.get_style().background = Fill::RadialGradient(Box::new(background.into()));
655 self
656 }
657
658 fn border(mut self, border: impl Into<Option<Border>>) -> Self {
659 if let Some(border) = border.into() {
660 self.get_style().borders.push(border);
661 }
662 self
663 }
664
665 fn shadow(mut self, shadow: impl Into<Shadow>) -> Self {
666 self.get_style().shadows.push(shadow.into());
667 self
668 }
669
670 fn corner_radius(mut self, corner_radius: impl Into<CornerRadius>) -> Self {
671 self.get_style().corner_radius = corner_radius.into();
672 self
673 }
674}
675
676impl<T: StyleExt> CornerRadiusExt for T {
677 fn with_corner_radius(mut self, corner_radius: f32) -> Self {
678 self.get_style().corner_radius = CornerRadius::new_all(corner_radius);
679 self
680 }
681}
682
683pub trait CornerRadiusExt: Sized {
684 fn with_corner_radius(self, corner_radius: f32) -> Self;
685
686 fn rounded_none(self) -> Self {
688 self.with_corner_radius(0.)
689 }
690
691 fn rounded(self) -> Self {
693 self.with_corner_radius(6.)
694 }
695
696 fn rounded_sm(self) -> Self {
698 self.with_corner_radius(4.)
699 }
700
701 fn rounded_md(self) -> Self {
703 self.with_corner_radius(6.)
704 }
705
706 fn rounded_lg(self) -> Self {
708 self.with_corner_radius(8.)
709 }
710
711 fn rounded_xl(self) -> Self {
713 self.with_corner_radius(12.)
714 }
715
716 fn rounded_2xl(self) -> Self {
718 self.with_corner_radius(16.)
719 }
720
721 fn rounded_3xl(self) -> Self {
723 self.with_corner_radius(24.)
724 }
725
726 fn rounded_4xl(self) -> Self {
728 self.with_corner_radius(32.)
729 }
730
731 fn rounded_full(self) -> Self {
733 self.with_corner_radius(99.)
734 }
735}
736
737pub trait MaybeExt
738where
739 Self: Sized,
740{
741 fn maybe(self, bool: impl Into<bool>, then: impl FnOnce(Self) -> Self) -> Self {
742 if bool.into() { then(self) } else { self }
743 }
744
745 fn map<T>(self, data: Option<T>, then: impl FnOnce(Self, T) -> Self) -> Self {
746 if let Some(data) = data {
747 then(self, data)
748 } else {
749 self
750 }
751 }
752}
753
754pub trait LayerExt
755where
756 Self: Sized,
757{
758 fn get_layer(&mut self) -> &mut Layer;
759
760 fn layer(mut self, layer: impl Into<Layer>) -> Self {
761 *self.get_layer() = layer.into();
762 self
763 }
764}
765
766pub trait ScrollableExt
767where
768 Self: Sized,
769{
770 fn get_effect(&mut self) -> &mut EffectData;
771
772 fn scrollable(mut self, scrollable: impl Into<bool>) -> Self {
773 self.get_effect().scrollable = scrollable.into();
774 self
775 }
776}
777
778pub trait InteractiveExt
779where
780 Self: Sized,
781{
782 fn get_effect(&mut self) -> &mut EffectData;
783
784 fn interactive(mut self, interactive: impl Into<Interactive>) -> Self {
785 self.get_effect().interactive = interactive.into();
786 self
787 }
788}
789
790pub trait EffectExt: Sized {
791 fn get_effect(&mut self) -> &mut EffectData;
792
793 fn effect(mut self, effect: EffectData) -> Self {
794 *self.get_effect() = effect;
795 self
796 }
797
798 fn overflow(mut self, overflow: impl Into<Overflow>) -> Self {
799 self.get_effect().overflow = overflow.into();
800 self
801 }
802
803 fn blur(mut self, blur: impl Into<f32>) -> Self {
804 self.get_effect().blur = Some(blur.into());
805 self
806 }
807
808 fn rotation(mut self, rotation: impl Into<f32>) -> Self {
809 self.get_effect().rotation = Some(rotation.into());
810 self
811 }
812
813 fn opacity(mut self, opacity: impl Into<f32>) -> Self {
814 self.get_effect().opacity = Some(opacity.into());
815 self
816 }
817
818 fn scale(mut self, scale: impl Into<Scale>) -> Self {
819 self.get_effect().scale = Some(scale.into());
820 self
821 }
822}