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