element.rs

  1use crate::Bounds;
  2
  3use super::{LayoutId, Pixels, Point, Result, ViewContext};
  4pub(crate) use smallvec::SmallVec;
  5
  6pub trait Element: 'static {
  7    type State;
  8    type FrameState;
  9
 10    fn layout(
 11        &mut self,
 12        state: &mut Self::State,
 13        cx: &mut ViewContext<Self::State>,
 14    ) -> Result<(LayoutId, Self::FrameState)>;
 15
 16    fn paint(
 17        &mut self,
 18        bounds: Bounds<Pixels>,
 19        state: &mut Self::State,
 20        frame_state: &mut Self::FrameState,
 21        cx: &mut ViewContext<Self::State>,
 22    ) -> Result<()>;
 23}
 24
 25pub trait ParentElement {
 26    type State;
 27
 28    fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<Self::State>; 2]>;
 29
 30    fn child(mut self, child: impl IntoAnyElement<Self::State>) -> Self
 31    where
 32        Self: Sized,
 33    {
 34        self.children_mut().push(child.into_any());
 35        self
 36    }
 37
 38    fn children(mut self, iter: impl IntoIterator<Item = impl IntoAnyElement<Self::State>>) -> Self
 39    where
 40        Self: Sized,
 41    {
 42        self.children_mut()
 43            .extend(iter.into_iter().map(|item| item.into_any()));
 44        self
 45    }
 46
 47    // HACK: This is a temporary hack to get children working for the purposes
 48    // of building UI on top of the current version of gpui2.
 49    //
 50    // We'll (hopefully) be moving away from this in the future.
 51    fn children_any<I>(mut self, children: I) -> Self
 52    where
 53        I: IntoIterator<Item = AnyElement<Self::State>>,
 54        Self: Sized,
 55    {
 56        self.children_mut().extend(children.into_iter());
 57        self
 58    }
 59
 60    // HACK: This is a temporary hack to get children working for the purposes
 61    // of building UI on top of the current version of gpui2.
 62    //
 63    // We'll (hopefully) be moving away from this in the future.
 64    fn child_any(mut self, children: AnyElement<Self::State>) -> Self
 65    where
 66        Self: Sized,
 67    {
 68        self.children_mut().push(children);
 69        self
 70    }
 71}
 72
 73trait ElementObject<S> {
 74    fn layout(&mut self, state: &mut S, cx: &mut ViewContext<S>) -> Result<LayoutId>;
 75    fn paint(
 76        &mut self,
 77        state: &mut S,
 78        offset: Option<Point<Pixels>>,
 79        cx: &mut ViewContext<S>,
 80    ) -> Result<()>;
 81}
 82
 83struct RenderedElement<E: Element> {
 84    element: E,
 85    phase: ElementRenderPhase<E::FrameState>,
 86}
 87
 88#[derive(Default)]
 89enum ElementRenderPhase<S> {
 90    #[default]
 91    Rendered,
 92    LayoutRequested {
 93        layout_id: LayoutId,
 94        frame_state: S,
 95    },
 96    Painted {
 97        bounds: Bounds<Pixels>,
 98        frame_state: S,
 99    },
100}
101
102/// Internal struct that wraps an element to store Layout and FrameState after the element is rendered.
103/// It's allocated as a trait object to erase the element type and wrapped in AnyElement<E::State> for
104/// improved usability.
105impl<E: Element> RenderedElement<E> {
106    fn new(element: E) -> Self {
107        RenderedElement {
108            element,
109            phase: ElementRenderPhase::Rendered,
110        }
111    }
112}
113
114impl<E: Element> ElementObject<E::State> for RenderedElement<E> {
115    fn layout(&mut self, state: &mut E::State, cx: &mut ViewContext<E::State>) -> Result<LayoutId> {
116        let (layout_id, frame_state) = self.element.layout(state, cx)?;
117        self.phase = ElementRenderPhase::LayoutRequested {
118            layout_id,
119            frame_state,
120        };
121        Ok(layout_id)
122    }
123
124    fn paint(
125        &mut self,
126        state: &mut E::State,
127        offset: Option<Point<Pixels>>,
128        cx: &mut ViewContext<E::State>,
129    ) -> Result<()> {
130        self.phase = match std::mem::take(&mut self.phase) {
131            ElementRenderPhase::Rendered => panic!("must call layout before paint"),
132
133            ElementRenderPhase::LayoutRequested {
134                layout_id,
135                mut frame_state,
136            } => {
137                let mut bounds = cx.layout_bounds(layout_id)?.clone();
138                offset.map(|offset| bounds.origin += offset);
139                self.element.paint(bounds, state, &mut frame_state, cx)?;
140                ElementRenderPhase::Painted {
141                    bounds,
142                    frame_state,
143                }
144            }
145
146            ElementRenderPhase::Painted {
147                bounds,
148                mut frame_state,
149            } => {
150                self.element
151                    .paint(bounds.clone(), state, &mut frame_state, cx)?;
152                ElementRenderPhase::Painted {
153                    bounds,
154                    frame_state,
155                }
156            }
157        };
158
159        Ok(())
160    }
161}
162
163pub struct AnyElement<S>(Box<dyn ElementObject<S>>);
164
165impl<S> AnyElement<S> {
166    pub fn layout(&mut self, state: &mut S, cx: &mut ViewContext<S>) -> Result<LayoutId> {
167        self.0.layout(state, cx)
168    }
169
170    pub fn paint(
171        &mut self,
172        state: &mut S,
173        offset: Option<Point<Pixels>>,
174        cx: &mut ViewContext<S>,
175    ) -> Result<()> {
176        self.0.paint(state, offset, cx)
177    }
178}
179
180pub trait IntoAnyElement<S> {
181    fn into_any(self) -> AnyElement<S>;
182}
183
184impl<E: Element> IntoAnyElement<E::State> for E {
185    fn into_any(self) -> AnyElement<E::State> {
186        AnyElement(Box::new(RenderedElement::new(self)))
187    }
188}
189
190impl<S> IntoAnyElement<S> for AnyElement<S> {
191    fn into_any(self) -> AnyElement<S> {
192        self
193    }
194}