Skip to main content

rgpui_component/
element_ext.rs

1use rgpui::{
2    AnyElement, App, Bounds, IntoElement, ParentElement, Pixels, Styled as _, Window, canvas,
3};
4
5use crate::{Sizable, Size};
6
7#[derive(Default)]
8struct ChildElementOptions {
9    ix: usize,
10    size: Size,
11}
12
13#[allow(patterns_in_fns_without_body)]
14pub trait ChildElement: Sizable + IntoElement {
15    fn with_ix(mut self, ix: usize) -> Self;
16}
17
18/// A type-erased element that can accept a [`AnyChildElementOptions`] before being rendered.
19pub struct AnyChildElement(Box<dyn FnOnce(ChildElementOptions) -> AnyElement>);
20
21impl AnyChildElement {
22    pub fn new(element: impl ChildElement + 'static) -> Self {
23        Self(Box::new(|options| {
24            element
25                .with_ix(options.ix)
26                .with_size(options.size)
27                .into_any_element()
28        }))
29    }
30
31    pub fn into_any(self, ix: usize, size: Size) -> AnyElement {
32        (self.0)(ChildElementOptions { ix, size })
33    }
34}
35
36/// A trait to extend [`gpui::Element`] with additional functionality.
37pub trait ElementExt: ParentElement + Sized {
38    /// Add a prepaint callback to the element.
39    ///
40    /// This is a helper method to get the bounds of the element after paint.
41    ///
42    /// The first argument is the bounds of the element in pixels.
43    ///
44    /// See also [`gpui::canvas`].
45    fn on_prepaint<F>(self, f: F) -> Self
46    where
47        F: FnOnce(Bounds<Pixels>, &mut Window, &mut App) + 'static,
48    {
49        self.child(
50            canvas(
51                move |bounds, window, cx| f(bounds, window, cx),
52                |_, _, _, _| {},
53            )
54            .absolute()
55            .size_full(),
56        )
57    }
58}
59
60impl<T: ParentElement> ElementExt for T {}