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