element.rs

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