Skip to main content

freya_core/elements/
extensions.rs

1use std::{
2    borrow::Cow,
3    hash::{
4        Hash,
5        Hasher,
6    },
7};
8
9use paste::paste;
10use ragnarok::CursorPoint;
11use rustc_hash::FxHasher;
12use torin::{
13    content::Content,
14    gaps::Gaps,
15    prelude::{
16        Alignment,
17        Direction,
18        Length,
19        Position,
20        VisibleSize,
21    },
22    size::Size,
23};
24
25use crate::{
26    data::{
27        AccessibilityData,
28        EffectData,
29        LayoutData,
30        Overflow,
31        TextStyleData,
32    },
33    diff_key::DiffKey,
34    element::{
35        Element,
36        EventHandlerType,
37        EventHandlers,
38    },
39    elements::image::{
40        AspectRatio,
41        ImageCover,
42        ImageData,
43        SamplingMode,
44    },
45    event_handler::EventHandler,
46    events::{
47        data::{
48            Event,
49            KeyboardEventData,
50            MouseEventData,
51            SizedEventData,
52            StyledEventData,
53            VisibleEventData,
54            WheelEventData,
55        },
56        name::EventName,
57    },
58    layers::Layer,
59    prelude::*,
60    style::{
61        font_size::FontSize,
62        font_slant::FontSlant,
63        font_weight::FontWeight,
64        font_width::FontWidth,
65        letter_spacing::LetterSpacing,
66        scale::Scale,
67        text_height::TextHeightBehavior,
68        text_overflow::TextOverflow,
69        text_shadow::TextShadow,
70        transform_origin::TransformOrigin,
71    },
72};
73
74/// Trait for composing child elements.
75pub trait ChildrenExt: Sized {
76    /// Returns a mutable reference to the internal children vector.
77    ///
78    /// # Example
79    /// ```ignore
80    /// impl ChildrenExt for MyElement {
81    ///     fn get_children(&mut self) -> &mut Vec<Element> {
82    ///         &mut self.elements
83    ///     }
84    /// }
85    /// ```
86    fn get_children(&mut self) -> &mut Vec<Element>;
87
88    /// Extends the children with an iterable of anything that implements [`IntoElement`].
89    ///
90    /// # Example
91    /// ```ignore
92    /// rect().children(["Hello", "World"].map(|t| label().text(t)))
93    /// ```
94    fn children(mut self, children: impl IntoIterator<Item = impl IntoElement>) -> Self {
95        self.get_children()
96            .extend(children.into_iter().map(IntoElement::into_element));
97        self
98    }
99
100    /// Appends a child only when the [`Option`] is [`Some`].
101    ///
102    /// # Example
103    /// ```ignore
104    /// rect().maybe_child(show_badge.then(|| label().text("New")))
105    /// ```
106    fn maybe_child<C: IntoElement>(mut self, child: Option<C>) -> Self {
107        if let Some(child) = child {
108            self.get_children().push(child.into_element());
109        }
110        self
111    }
112
113    /// Appends a single child element.
114    ///
115    /// # Example
116    /// ```ignore
117    /// rect().child(label().text("Hello"))
118    /// ```
119    fn child<C: IntoElement>(mut self, child: C) -> Self {
120        self.get_children().push(child.into_element());
121        self
122    }
123}
124
125/// Trait for giving an element a stable identity across renders.
126pub trait KeyExt: Sized {
127    /// Returns a mutable reference to the element's diff key.
128    fn write_key(&mut self) -> &mut DiffKey;
129
130    /// Assign a key derived from any hashable value, used to reconcile elements in dynamic lists.
131    /// The key is scoped to the element's type, so the same value used
132    /// on different element or component types never collides.
133    fn key(mut self, key: impl Hash) -> Self
134    where
135        Self: 'static,
136    {
137        let mut hasher = FxHasher::default();
138        std::any::TypeId::of::<Self>().hash(&mut hasher);
139        key.hash(&mut hasher);
140        *self.write_key() = DiffKey::U64(hasher.finish());
141        self
142    }
143}
144
145/// Trait for concatenating two lists into one.
146pub trait ListExt {
147    /// Append the contents of `other`, returning the combined list.
148    fn with(self, other: Self) -> Self;
149}
150
151impl<T> ListExt for Vec<T> {
152    fn with(mut self, other: Self) -> Self {
153        self.extend(other);
154        self
155    }
156}
157
158macro_rules! event_handlers {
159    (
160        $handler_variant:ident, $event_data:ty;
161        $(
162            $(#[$attr:meta])*
163            $name:ident => $event_variant:expr ;
164        )*
165    ) => {
166        paste! {
167            $(
168                $(#[$attr])*
169                fn [<on_$name>](mut self, [<on_$name>]: impl Into<EventHandler<Event<$event_data>>>) -> Self {
170                    self.get_event_handlers()
171                        .insert($event_variant, EventHandlerType::$handler_variant([<on_$name>].into()));
172                    self
173                }
174            )*
175        }
176    };
177}
178
179/// Methods for attaching event handlers to an element.
180///
181/// Many events come in three flavors: the plain one fires only while the pointer is over the
182/// element, the `global_` variants fire no matter where the event happens, and the `capture_`
183/// variants fire during the top-down capture phase, before the event reaches the inner element.
184///
185/// For high-level press handling, prefer [`on_press`](EventHandlersExt::on_press) over the raw mouse/pointer events.
186pub trait EventHandlersExt: Sized {
187    /// Returns a mutable reference to the element's event handler map.
188    fn get_event_handlers(&mut self) -> &mut EventHandlers;
189
190    /// Replace all of this element's event handlers with the given map.
191    fn event_handlers(mut self, event_handlers: EventHandlers) -> Self {
192        *self.get_event_handlers() = event_handlers;
193        self
194    }
195
196    event_handlers! {
197        Mouse,
198        MouseEventData;
199
200        /// Fires when a mouse button is pressed down over the element.
201        mouse_down => EventName::MouseDown;
202        /// Fires when a mouse button is released over the element.
203        mouse_up => EventName::MouseUp;
204        /// Fires when the cursor moves over the element.
205        mouse_move => EventName::MouseMove;
206
207    }
208
209    event_handlers! {
210        Pointer,
211        PointerEventData;
212
213        /// Fires when a pointer (mouse or touch) is pressed anywhere, even outside the element.
214        global_pointer_press => EventName::GlobalPointerPress;
215        /// Fires when a pointer (mouse or touch) goes down anywhere, even outside the element.
216        global_pointer_down => EventName::GlobalPointerDown;
217        /// Fires when a pointer (mouse or touch) moves anywhere, even outside the element.
218        global_pointer_move => EventName::GlobalPointerMove;
219
220        /// Like [`on_global_pointer_move`](Self::on_global_pointer_move), but fires during the top-down capture phase.
221        capture_global_pointer_move => EventName::CaptureGlobalPointerMove;
222        /// Like [`on_global_pointer_press`](Self::on_global_pointer_press), but fires during the top-down capture phase.
223        capture_global_pointer_press => EventName::CaptureGlobalPointerPress;
224    }
225
226    event_handlers! {
227        Keyboard,
228        KeyboardEventData;
229
230        /// Fires when a key is pressed down while the element is focused.
231        key_down => EventName::KeyDown;
232        /// Fires when a key is released while the element is focused.
233        key_up => EventName::KeyUp;
234
235        /// Fires when a key is pressed down, regardless of which element is focused.
236        global_key_down => EventName::GlobalKeyDown;
237        /// Fires when a key is released, regardless of which element is focused.
238        global_key_up => EventName::GlobalKeyUp;
239    }
240
241    event_handlers! {
242        Wheel,
243        WheelEventData;
244
245        /// Fires when the scroll wheel is used over the element.
246        wheel => EventName::Wheel;
247    }
248
249    event_handlers! {
250        Touch,
251        TouchEventData;
252
253        /// Fires when an ongoing touch is cancelled by the system.
254        touch_cancel => EventName::TouchCancel;
255        /// Fires when a touch point is placed on the element.
256        touch_start => EventName::TouchStart;
257        /// Fires when a touch point moves across the element.
258        touch_move => EventName::TouchMove;
259        /// Fires when a touch point is lifted from the element.
260        touch_end => EventName::TouchEnd;
261    }
262
263    event_handlers! {
264        Pointer,
265        PointerEventData;
266
267        /// Fires when the element is pressed and released by a pointer (mouse or touch).
268        pointer_press => EventName::PointerPress;
269        /// Fires when a pointer (mouse or touch) goes down over the element.
270        pointer_down => EventName::PointerDown;
271        /// Fires when a pointer (mouse or touch) moves over the element.
272        pointer_move => EventName::PointerMove;
273        /// Fires when a pointer enters the element.
274        pointer_enter => EventName::PointerEnter;
275        /// Fires when a pointer leaves the element.
276        pointer_leave => EventName::PointerLeave;
277        /// Fires when a pointer is over the element, including over its children.
278        pointer_over => EventName::PointerOver;
279        /// Fires when a pointer leaves the element or one of its children.
280        pointer_out => EventName::PointerOut;
281    }
282
283    event_handlers! {
284        File,
285        FileEventData;
286
287        /// Fires when a file is dropped onto the element.
288        file_drop => EventName::FileDrop;
289        /// Fires when a dragged file hovers anywhere over the window.
290        global_file_hover => EventName::GlobalFileHover;
291        /// Fires when a dragged file stops hovering over the window.
292        global_file_hover_cancelled => EventName::GlobalFileHoverCancelled;
293    }
294
295    event_handlers! {
296        ImePreedit,
297        ImePreeditEventData;
298
299        /// Fires while text is being composed through an input method editor (IME).
300        ime_preedit => EventName::ImePreedit;
301    }
302
303    /// Fires when the element's measured size or position changes.
304    fn on_sized(mut self, on_sized: impl Into<EventHandler<Event<SizedEventData>>>) -> Self
305    where
306        Self: LayoutExt,
307    {
308        self.get_event_handlers()
309            .insert(EventName::Sized, EventHandlerType::Sized(on_sized.into()));
310        self.get_layout().layout.has_layout_references = true;
311        self
312    }
313
314    /// Fires when the element becomes visible, even partially, inside the viewports of its clipping ancestors.
315    fn on_visible(mut self, on_visible: impl Into<EventHandler<Event<VisibleEventData>>>) -> Self {
316        self.get_event_handlers().insert(
317            EventName::Visible,
318            EventHandlerType::Visible(on_visible.into()),
319        );
320        self
321    }
322
323    /// Fires when the element stops being visible inside the viewports of its clipping ancestors.
324    fn on_hidden(mut self, on_hidden: impl Into<EventHandler<Event<VisibleEventData>>>) -> Self {
325        self.get_event_handlers().insert(
326            EventName::Hidden,
327            EventHandlerType::Visible(on_hidden.into()),
328        );
329        self
330    }
331
332    /// Fires when the element's inherited text style is resolved or changes.
333    fn on_styled(mut self, on_styled: impl Into<EventHandler<Event<StyledEventData>>>) -> Self {
334        self.get_event_handlers().insert(
335            EventName::Styled,
336            EventHandlerType::Styled(on_styled.into()),
337        );
338        self
339    }
340
341    /// This is generally the best event in which to run "press" logic, this might be called `onClick`, `onActivate`, or `onConnect` in other platforms.
342    ///
343    /// Gets triggered when:
344    /// - **Click**: There is a `MouseUp` event (Left button) with the in the same element that there had been a `MouseDown` just before
345    /// - **Touched**: There is a `TouchEnd` event in the same element that there had been a `TouchStart` just before
346    /// - **Activated**: The element is focused and there is a keydown event pressing the OS activation key (e.g Space, Enter)
347    fn on_press(self, on_press: impl Into<EventHandler<Event<PressEventData>>>) -> Self {
348        let on_press = on_press.into();
349        self.on_pointer_press({
350            let on_press = on_press.clone();
351            move |e: Event<PointerEventData>| {
352                let event = e.try_map(|d| match d {
353                    PointerEventData::Mouse(m) if m.button == Some(MouseButton::Left) => {
354                        Some(PressEventData::Mouse(m))
355                    }
356                    PointerEventData::Touch(t) => Some(PressEventData::Touch(t)),
357                    _ => None,
358                });
359                if let Some(event) = event {
360                    on_press.call(event);
361                }
362            }
363        })
364        .on_key_down(move |e: Event<KeyboardEventData>| {
365            if e.is_press_event() {
366                on_press.call(e.map(PressEventData::Keyboard))
367            }
368        })
369    }
370
371    /// Also called the context menu click in other platforms.
372    /// Gets triggered when:
373    /// - **Click**: There is a `MouseDown` (Right button) event
374    fn on_secondary_down(
375        self,
376        on_secondary_down: impl Into<EventHandler<Event<PressEventData>>>,
377    ) -> Self {
378        let on_secondary_down = on_secondary_down.into();
379        self.on_pointer_down(move |e: Event<PointerEventData>| {
380            let event = e.try_map(|d| match d {
381                PointerEventData::Mouse(m) if m.button == Some(MouseButton::Right) => {
382                    Some(PressEventData::Mouse(m))
383                }
384                _ => None,
385            });
386            if let Some(event) = event {
387                on_secondary_down.call(event);
388            }
389        })
390    }
391
392    /// Gets triggered when:
393    /// - **Click**: There is a `MouseUp` event (Any button) with the in the same element that there had been a `MouseDown` just before
394    /// - **Touched**: There is a `TouchEnd` event in the same element that there had been a `TouchStart` just before
395    /// - **Activated**: The element is focused and there is a keydown event pressing the OS activation key (e.g Space, Enter)
396    fn on_all_press(self, on_press: impl Into<EventHandler<Event<PressEventData>>>) -> Self {
397        let on_press = on_press.into();
398        self.on_pointer_press({
399            let on_press = on_press.clone();
400            move |e: Event<PointerEventData>| {
401                let event = e.map(|d| match d {
402                    PointerEventData::Mouse(m) => PressEventData::Mouse(m),
403                    PointerEventData::Touch(t) => PressEventData::Touch(t),
404                });
405                on_press.call(event);
406            }
407        })
408        .on_key_down(move |e: Event<KeyboardEventData>| {
409            if e.is_press_event() {
410                on_press.call(e.map(PressEventData::Keyboard))
411            }
412        })
413    }
414    /// Gets triggered when:
415    /// - **Started clicking**: There is a `MouseDown` event (Left button)
416    /// - **Touched**: There is a `TouchEnd` event in the same element that there had been a `TouchStart` just before
417    ///
418    /// This event is intended to focus elements such as text inputs following each platform style.
419    fn on_focus_press(
420        self,
421        on_focus_press: impl Into<EventHandler<Event<FocusPressEventData>>>,
422    ) -> Self {
423        let on_focus_press = on_focus_press.into();
424        if cfg!(target_os = "android") {
425            self.on_pointer_press(move |e: Event<PointerEventData>| {
426                let event = e.try_map(|d| match d {
427                    PointerEventData::Mouse(m) if m.button == Some(MouseButton::Left) => {
428                        Some(FocusPressEventData::Mouse(m))
429                    }
430                    PointerEventData::Touch(t) => Some(FocusPressEventData::Touch(t)),
431                    _ => None,
432                });
433                if let Some(event) = event {
434                    on_focus_press.call(event);
435                }
436            })
437        } else {
438            self.on_pointer_down(move |e: Event<PointerEventData>| {
439                let event = e.try_map(|d| match d {
440                    PointerEventData::Mouse(m) if m.button == Some(MouseButton::Left) => {
441                        Some(FocusPressEventData::Mouse(m))
442                    }
443                    PointerEventData::Touch(t) => Some(FocusPressEventData::Touch(t)),
444                    _ => None,
445                });
446                if let Some(event) = event {
447                    on_focus_press.call(event);
448                }
449            })
450        }
451    }
452}
453
454/// Data delivered to [`on_focus_press`](EventHandlersExt::on_focus_press), which can originate from a mouse or a touch.
455#[derive(Debug, Clone, PartialEq)]
456pub enum FocusPressEventData {
457    Mouse(MouseEventData),
458    Touch(TouchEventData),
459}
460
461impl FocusPressEventData {
462    pub fn global_location(&self) -> CursorPoint {
463        match self {
464            Self::Mouse(m) => m.global_location,
465            Self::Touch(t) => t.global_location,
466        }
467    }
468
469    pub fn element_location(&self) -> CursorPoint {
470        match self {
471            Self::Mouse(m) => m.element_location,
472            Self::Touch(t) => t.element_location,
473        }
474    }
475
476    pub fn button(&self) -> Option<MouseButton> {
477        match self {
478            Self::Mouse(m) => m.button,
479            Self::Touch(_) => None,
480        }
481    }
482}
483
484/// Data delivered to [`on_press`](EventHandlersExt::on_press), which can originate from a mouse, the keyboard or a touch.
485#[derive(Debug, Clone, PartialEq)]
486pub enum PressEventData {
487    Mouse(MouseEventData),
488    Keyboard(KeyboardEventData),
489    Touch(TouchEventData),
490}
491
492/// Layout methods for containers that arrange children along a direction axis.
493pub trait ContainerWithContentExt
494where
495    Self: LayoutExt,
496{
497    /// Set the axis children are stacked along. See [`Direction`].
498    fn direction(mut self, direction: Direction) -> Self {
499        self.get_layout().layout.direction = direction;
500        self
501    }
502    /// Set how children are aligned along the direction axis. See [`Alignment`].
503    fn main_align(mut self, main_align: impl Into<Alignment>) -> Self {
504        self.get_layout().layout.main_alignment = main_align.into();
505        self
506    }
507
508    /// Set how children are aligned across the direction axis. See [`Alignment`].
509    fn cross_align(mut self, cross_align: impl Into<Alignment>) -> Self {
510        self.get_layout().layout.cross_alignment = cross_align.into();
511        self
512    }
513
514    /// Set the gap inserted between adjacent children, in pixels.
515    fn spacing(mut self, spacing: f32) -> Self {
516        self.get_layout().layout.spacing = Length::new(spacing);
517        self
518    }
519
520    /// Set how children share the available space along the direction axis. See [`Content`].
521    fn content(mut self, content: Content) -> Self {
522        self.get_layout().layout.content = content;
523        self
524    }
525    /// Center children on both axes. Shorthand for [`main_align`](Self::main_align) and [`cross_align`](Self::cross_align) set to [`Alignment::Center`].
526    fn center(mut self) -> Self {
527        self.get_layout().layout.main_alignment = Alignment::Center;
528        self.get_layout().layout.cross_alignment = Alignment::Center;
529
530        self
531    }
532
533    /// Shift the element's children horizontally by the given pixels.
534    fn offset_x(mut self, offset_x: f32) -> Self {
535        self.get_layout().layout.offset_x = Length::new(offset_x);
536        self
537    }
538
539    /// Shift the element's children vertically by the given pixels.
540    fn offset_y(mut self, offset_y: f32) -> Self {
541        self.get_layout().layout.offset_y = Length::new(offset_y);
542        self
543    }
544
545    /// Stack children vertically. Shorthand for [`direction`](Self::direction) set to [`Direction::Vertical`].
546    fn vertical(mut self) -> Self {
547        self.get_layout().layout.direction = Direction::vertical();
548        self
549    }
550
551    /// Stack children horizontally. Shorthand for [`direction`](Self::direction) set to [`Direction::Horizontal`].
552    fn horizontal(mut self) -> Self {
553        self.get_layout().layout.direction = Direction::horizontal();
554        self
555    }
556}
557
558/// Methods for setting an element's width and height.
559pub trait ContainerSizeExt
560where
561    Self: LayoutExt,
562{
563    /// Set the element's width. See [`Size`].
564    fn width(mut self, width: impl Into<Size>) -> Self {
565        self.get_layout().layout.width = width.into();
566        self
567    }
568
569    /// Set the element's height. See [`Size`].
570    fn height(mut self, height: impl Into<Size>) -> Self {
571        self.get_layout().layout.height = height.into();
572        self
573    }
574
575    /// Expand both `width` and `height` using [Size::fill()].
576    fn expanded(mut self) -> Self {
577        self.get_layout().layout.width = Size::fill();
578        self.get_layout().layout.height = Size::fill();
579        self
580    }
581}
582
583impl<T: ContainerExt> ContainerSizeExt for T {}
584
585/// Methods for setting how an element is placed relative to its parent or the window.
586pub trait ContainerPositionExt
587where
588    Self: LayoutExt,
589{
590    /// Set how the element is placed relative to its parent or the window. See [`Position`].
591    fn position(mut self, position: impl Into<Position>) -> Self {
592        self.get_layout().layout.position = position.into();
593        self
594    }
595
596    /// Set the outer spacing between the element's edges and its surroundings. See [`Gaps`].
597    fn margin(mut self, margin: impl Into<Gaps>) -> Self {
598        self.get_layout().layout.margin = margin.into();
599        self
600    }
601}
602
603impl<T: ContainerExt> ContainerPositionExt for T {}
604
605/// Method for setting an element's inner padding.
606pub trait ContainerExt
607where
608    Self: LayoutExt,
609{
610    /// Set the inner spacing between the element's edges and its content. See [`Gaps`].
611    fn padding(mut self, padding: impl Into<Gaps>) -> Self {
612        self.get_layout().layout.padding = padding.into();
613        self
614    }
615}
616
617/// Methods for setting an element's size constraints.
618pub trait ContainerConstraintsExt
619where
620    Self: LayoutExt,
621{
622    /// Set the minimum width the element can shrink to. See [`Size`].
623    fn min_width(mut self, minimum_width: impl Into<Size>) -> Self {
624        self.get_layout().layout.minimum_width = minimum_width.into();
625        self
626    }
627
628    /// Set the minimum height the element can shrink to. See [`Size`].
629    fn min_height(mut self, minimum_height: impl Into<Size>) -> Self {
630        self.get_layout().layout.minimum_height = minimum_height.into();
631        self
632    }
633
634    /// Set the maximum width the element can grow to. See [`Size`].
635    fn max_width(mut self, maximum_width: impl Into<Size>) -> Self {
636        self.get_layout().layout.maximum_width = maximum_width.into();
637        self
638    }
639
640    /// Set the maximum height the element can grow to. See [`Size`].
641    fn max_height(mut self, maximum_height: impl Into<Size>) -> Self {
642        self.get_layout().layout.maximum_height = maximum_height.into();
643        self
644    }
645
646    /// Set how much of the measured width is actually used in layout. See [`VisibleSize`].
647    fn visible_width(mut self, visible_width: impl Into<VisibleSize>) -> Self {
648        self.get_layout().layout.visible_width = visible_width.into();
649        self
650    }
651
652    /// Set how much of the measured height is actually used in layout. See [`VisibleSize`].
653    fn visible_height(mut self, visible_height: impl Into<VisibleSize>) -> Self {
654        self.get_layout().layout.visible_height = visible_height.into();
655        self
656    }
657}
658
659impl<T: ContainerExt> ContainerConstraintsExt for T {}
660
661/// Low-level access to an element's [`LayoutData`].
662pub trait LayoutExt
663where
664    Self: Sized,
665{
666    /// Returns a mutable reference to the element's layout data.
667    fn get_layout(&mut self) -> &mut LayoutData;
668
669    /// Replace all of the element's layout data at once. See [`LayoutData`].
670    fn layout(mut self, layout: LayoutData) -> Self {
671        *self.get_layout() = layout;
672        self
673    }
674}
675
676/// Methods for configuring how an image is scaled and sampled.
677pub trait ImageExt
678where
679    Self: LayoutExt,
680{
681    /// Returns a mutable reference to the element's image data.
682    fn get_image_data(&mut self) -> &mut ImageData;
683
684    /// Replace all of the element's image data at once. See [`ImageData`].
685    fn image_data(mut self, image_data: ImageData) -> Self {
686        *self.get_image_data() = image_data;
687        self
688    }
689
690    /// Set the filtering used when the image is scaled. See [`SamplingMode`].
691    fn sampling_mode(mut self, sampling_mode: SamplingMode) -> Self {
692        self.get_image_data().sampling_mode = sampling_mode;
693        self
694    }
695
696    /// Set how the image is scaled to fit its bounds. See [`AspectRatio`].
697    fn aspect_ratio(mut self, aspect_ratio: AspectRatio) -> Self {
698        self.get_image_data().aspect_ratio = aspect_ratio;
699        self
700    }
701
702    /// Set how the image is positioned within its bounds. See [`ImageCover`].
703    fn image_cover(mut self, image_cover: ImageCover) -> Self {
704        self.get_image_data().image_cover = image_cover;
705        self
706    }
707
708    /// Snap the image to the pixels grid. Defaults to `false`, but `SvgViewer` enables it.
709    fn snap_to_grid(mut self, snap_to_grid: bool) -> Self {
710        self.get_image_data().snap_to_grid = snap_to_grid;
711        self
712    }
713}
714
715/// Methods for describing an element in the accessibility tree.
716pub trait AccessibilityExt: Sized {
717    /// Returns a mutable reference to the element's accessibility data.
718    fn get_accessibility_data(&mut self) -> &mut AccessibilityData;
719
720    /// Replace all of the element's accessibility data at once. See [`AccessibilityData`].
721    fn accessibility(mut self, accessibility: AccessibilityData) -> Self {
722        *self.get_accessibility_data() = accessibility;
723        self
724    }
725
726    /// Set an explicit accessibility id instead of an autogenerated one. See [`AccessibilityId`].
727    fn a11y_id(mut self, a11y_id: impl Into<Option<AccessibilityId>>) -> Self {
728        self.get_accessibility_data().a11y_id = a11y_id.into();
729        self
730    }
731
732    /// Set whether the element can receive keyboard focus. See [`Focusable`].
733    fn a11y_focusable(mut self, a11y_focusable: impl Into<Focusable>) -> Self {
734        self.get_accessibility_data().a11y_focusable = a11y_focusable.into();
735        self
736    }
737
738    /// Request that the element be focused automatically when it is mounted.
739    fn a11y_auto_focus(mut self, a11y_auto_focus: impl Into<bool>) -> Self {
740        self.get_accessibility_data().a11y_auto_focus = a11y_auto_focus.into();
741        self
742    }
743
744    /// Mark the element as a member of the group identified by the given [`AccessibilityId`].
745    fn a11y_member_of(mut self, a11y_member_of: impl Into<AccessibilityId>) -> Self {
746        self.get_accessibility_data()
747            .builder
748            .set_member_of(a11y_member_of.into());
749        self
750    }
751
752    /// Set the accessibility role exposed in the accessibility tree. See [`AccessibilityRole`].
753    fn a11y_role(mut self, a11y_role: impl Into<AccessibilityRole>) -> Self {
754        self.get_accessibility_data()
755            .builder
756            .set_role(a11y_role.into());
757        self
758    }
759
760    /// Set the text label that describes the element in the accessibility tree.
761    fn a11y_alt(mut self, value: impl Into<Box<str>>) -> Self {
762        self.get_accessibility_data().builder.set_label(value);
763        self
764    }
765
766    /// Edit the underlying `accesskit` node directly for advanced accessibility properties.
767    fn a11y_builder(mut self, with: impl FnOnce(&mut accesskit::Node)) -> Self {
768        with(&mut self.get_accessibility_data().builder);
769        self
770    }
771}
772
773/// Methods for styling the text rendered by an element and inherited by its children.
774pub trait TextStyleExt
775where
776    Self: Sized,
777{
778    /// Returns a mutable reference to the element's text style data.
779    fn get_text_style_data(&mut self) -> &mut TextStyleData;
780
781    /// Replace all of the element's text style data at once. See [`TextStyleData`].
782    fn text_style(mut self, data: TextStyleData) -> Self {
783        *self.get_text_style_data() = data;
784        self
785    }
786
787    /// Paint the text with any [`Fill`]: a [`Color`], a gradient or a shader.
788    fn color(mut self, color: impl Into<Fill>) -> Self {
789        self.get_text_style_data().color = Some(color.into());
790        self
791    }
792
793    /// Set the horizontal alignment of the text. See [`TextAlign`].
794    fn text_align(mut self, text_align: impl Into<TextAlign>) -> Self {
795        self.get_text_style_data().text_align = Some(text_align.into());
796        self
797    }
798
799    /// Set the text size in pixels. See [`FontSize`].
800    fn font_size(mut self, font_size: impl Into<FontSize>) -> Self {
801        self.get_text_style_data().font_size = Some(font_size.into());
802        self
803    }
804
805    /// Set the space between letters, in pixels. See [`LetterSpacing`].
806    fn letter_spacing(mut self, letter_spacing: impl Into<LetterSpacing>) -> Self {
807        self.get_text_style_data().letter_spacing = Some(letter_spacing.into());
808        self
809    }
810
811    /// Add a font family to try, in order of preference.
812    fn font_family(mut self, font_family: impl Into<Cow<'static, str>>) -> Self {
813        self.get_text_style_data()
814            .font_families
815            .push(font_family.into());
816        self
817    }
818
819    /// Set the slant (style) of the font. See [`FontSlant`].
820    fn font_slant(mut self, font_slant: impl Into<FontSlant>) -> Self {
821        self.get_text_style_data().font_slant = Some(font_slant.into());
822        self
823    }
824
825    /// Set the thickness of the font. See [`FontWeight`].
826    fn font_weight(mut self, font_weight: impl Into<FontWeight>) -> Self {
827        self.get_text_style_data().font_weight = Some(font_weight.into());
828        self
829    }
830
831    /// Set the horizontal width of the font. See [`FontWidth`].
832    fn font_width(mut self, font_width: impl Into<FontWidth>) -> Self {
833        self.get_text_style_data().font_width = Some(font_width.into());
834        self
835    }
836
837    /// Set how the leading of the first and last lines is handled. See [`TextHeightBehavior`].
838    fn text_height(mut self, text_height: impl Into<TextHeightBehavior>) -> Self {
839        self.get_text_style_data().text_height = Some(text_height.into());
840        self
841    }
842
843    /// Set how text that does not fit its bounds is truncated. See [`TextOverflow`].
844    fn text_overflow(mut self, text_overflow: impl Into<TextOverflow>) -> Self {
845        self.get_text_style_data().text_overflow = Some(text_overflow.into());
846        self
847    }
848
849    /// Add a shadow cast behind the text. See [`TextShadow`].
850    fn text_shadow(mut self, text_shadow: impl Into<TextShadow>) -> Self {
851        self.get_text_style_data()
852            .text_shadows
853            .push(text_shadow.into());
854        self
855    }
856
857    /// Set a line drawn through, under or over the text. See [`TextDecoration`].
858    fn text_decoration(mut self, text_decoration: impl Into<TextDecoration>) -> Self {
859        self.get_text_style_data().text_decoration = Some(text_decoration.into());
860        self
861    }
862}
863
864/// Methods for styling an element's box: background, borders, shadows and corners.
865pub trait StyleExt
866where
867    Self: Sized,
868{
869    /// Returns a mutable reference to the element's style data.
870    fn get_style(&mut self) -> &mut StyleState;
871
872    /// Replace all of the element's style data at once. See [`StyleState`].
873    fn style(mut self, style: StyleState) -> Self {
874        *self.get_style() = style;
875        self
876    }
877
878    /// Paint the background with any [`Fill`]: a [`Color`], a gradient or a shader.
879    fn background(mut self, background: impl Into<Fill>) -> Self {
880        self.get_style().background = background.into();
881        self
882    }
883
884    /// Add an outline around the element. See [`Border`].
885    fn border(mut self, border: impl Into<Option<Border>>) -> Self {
886        if let Some(border) = border.into() {
887            self.get_style().borders.push(border);
888        }
889        self
890    }
891
892    /// Add a shadow cast by the element. See [`Shadow`].
893    fn shadow(mut self, shadow: impl Into<Shadow>) -> Self {
894        self.get_style().shadows.push(shadow.into());
895        self
896    }
897
898    /// Round the element's corners. See [`CornerRadius`].
899    fn corner_radius(mut self, corner_radius: impl Into<CornerRadius>) -> Self {
900        self.get_style().corner_radius = corner_radius.into();
901        self
902    }
903
904    /// Set the [`CursorIcon`] shown while the element is hovered.
905    ///
906    /// When multiple hovered elements define a cursor, the one painted on top wins.
907    /// While a mouse button is pressed the cursor stays still.
908    fn cursor(mut self, cursor: impl Into<Option<CursorIcon>>) -> Self {
909        self.get_style().cursor = cursor.into();
910        self
911    }
912}
913
914impl<T: StyleExt> CornerRadiusExt for T {
915    fn with_corner_radius(mut self, corner_radius: f32) -> Self {
916        self.get_style().corner_radius = CornerRadius::new_all(corner_radius);
917        self
918    }
919}
920
921/// Shorthand methods for setting an element's [`CornerRadius`] to common values.
922pub trait CornerRadiusExt: Sized {
923    /// Round all four corners to the given radius in pixels.
924    fn with_corner_radius(self, corner_radius: f32) -> Self;
925
926    /// Shortcut for `corner_radius(0.)` - removes border radius.
927    fn rounded_none(self) -> Self {
928        self.with_corner_radius(0.)
929    }
930
931    /// Shortcut for `corner_radius(6.)` - default border radius.
932    fn rounded(self) -> Self {
933        self.with_corner_radius(6.)
934    }
935
936    /// Shortcut for `corner_radius(4.)` - small border radius.
937    fn rounded_sm(self) -> Self {
938        self.with_corner_radius(4.)
939    }
940
941    /// Shortcut for `corner_radius(6.)` - medium border radius.
942    fn rounded_md(self) -> Self {
943        self.with_corner_radius(6.)
944    }
945
946    /// Shortcut for `corner_radius(8.)` - large border radius.
947    fn rounded_lg(self) -> Self {
948        self.with_corner_radius(8.)
949    }
950
951    /// Shortcut for `corner_radius(12.)` - extra large border radius.
952    fn rounded_xl(self) -> Self {
953        self.with_corner_radius(12.)
954    }
955
956    /// Shortcut for `corner_radius(16.)` - extra large border radius.
957    fn rounded_2xl(self) -> Self {
958        self.with_corner_radius(16.)
959    }
960
961    /// Shortcut for `corner_radius(24.)` - extra large border radius.
962    fn rounded_3xl(self) -> Self {
963        self.with_corner_radius(24.)
964    }
965
966    /// Shortcut for `corner_radius(32.)` - extra large border radius.
967    fn rounded_4xl(self) -> Self {
968        self.with_corner_radius(32.)
969    }
970
971    /// Shortcut for `corner_radius(99.)` - fully rounded (pill shape).
972    fn rounded_full(self) -> Self {
973        self.with_corner_radius(99.)
974    }
975}
976
977/// Methods for applying changes to an element conditionally.
978pub trait MaybeExt
979where
980    Self: Sized,
981{
982    /// Apply `then` to the element only when the condition is `true`.
983    fn maybe(self, bool: impl Into<bool>, then: impl FnOnce(Self) -> Self) -> Self {
984        if bool.into() { then(self) } else { self }
985    }
986
987    /// Apply `then` to the element only when the [`Option`] is [`Some`], passing the inner value.
988    fn map<T>(self, data: Option<T>, then: impl FnOnce(Self, T) -> Self) -> Self {
989        if let Some(data) = data {
990            then(self, data)
991        } else {
992            self
993        }
994    }
995}
996
997/// Method for controlling which painting layer an element belongs to.
998pub trait LayerExt
999where
1000    Self: Sized,
1001{
1002    /// Returns a mutable reference to the element's layer.
1003    fn get_layer(&mut self) -> &mut Layer;
1004
1005    /// Set the painting layer of the element. See [`Layer`].
1006    fn layer(mut self, layer: impl Into<Layer>) -> Self {
1007        *self.get_layer() = layer.into();
1008        self
1009    }
1010}
1011
1012pub trait ScrollableExt
1013where
1014    Self: Sized,
1015{
1016    /// Returns a mutable reference to the element's effect data.
1017    fn get_effect(&mut self) -> &mut EffectData;
1018
1019    /// Mark this element as scrollable.
1020    /// You are probably looking for the `ScrollView` component instead.
1021    fn scrollable(mut self, scrollable: impl Into<bool>) -> Self {
1022        self.get_effect().scrollable = scrollable.into();
1023        self
1024    }
1025}
1026
1027/// Method for controlling whether an element responds to pointer events.
1028pub trait InteractiveExt
1029where
1030    Self: Sized,
1031{
1032    /// Returns a mutable reference to the element's effect data.
1033    fn get_effect(&mut self) -> &mut EffectData;
1034
1035    /// Set whether the element receives pointer events. See [`Interactive`].
1036    fn interactive(mut self, interactive: impl Into<Interactive>) -> Self {
1037        self.get_effect().interactive = interactive.into();
1038        self
1039    }
1040}
1041
1042/// Methods for visual effects applied to an element: clipping, blur, rotation, opacity and scale.
1043pub trait EffectExt: Sized {
1044    /// Returns a mutable reference to the element's effect data.
1045    fn get_effect(&mut self) -> &mut EffectData;
1046
1047    /// Replace all of the element's effect data at once. See [`EffectData`].
1048    fn effect(mut self, effect: EffectData) -> Self {
1049        *self.get_effect() = effect;
1050        self
1051    }
1052
1053    /// Set whether content overflowing the element's bounds is clipped. See [`Overflow`].
1054    fn overflow(mut self, overflow: impl Into<Overflow>) -> Self {
1055        self.get_effect().overflow = overflow.into();
1056        self
1057    }
1058
1059    /// Apply a gaussian blur of the given radius to the element.
1060    fn blur(mut self, blur: f32) -> Self {
1061        self.get_effect().blur = Some(blur);
1062        self
1063    }
1064
1065    /// Rotate the element by the given angle in degrees.
1066    fn rotation(mut self, rotation: f32) -> Self {
1067        self.get_effect().rotation = Some(rotation);
1068        self
1069    }
1070
1071    /// Set the element's opacity, from `0.0` (transparent) to `1.0` (opaque).
1072    fn opacity(mut self, opacity: f32) -> Self {
1073        self.get_effect().opacity = Some(opacity);
1074        self
1075    }
1076
1077    /// Scale the element. See [`Scale`].
1078    fn scale(mut self, scale: impl Into<Scale>) -> Self {
1079        self.get_effect().scale = Some(scale.into());
1080        self
1081    }
1082
1083    /// Set the point that the scale and rotation effects pivot around.
1084    ///
1085    /// Defaults to the element's center.
1086    fn transform_origin(mut self, transform_origin: impl Into<TransformOrigin>) -> Self {
1087        self.get_effect().transform_origin = transform_origin.into();
1088        self
1089    }
1090}