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