element.rs

  1pub use crate::layout_context::LayoutContext;
  2pub use crate::paint_context::PaintContext;
  3use anyhow::Result;
  4pub use gpui::{Layout, LayoutId};
  5use smallvec::SmallVec;
  6
  7pub trait Element<V: 'static>: 'static {
  8    type PaintState;
  9
 10    fn layout(
 11        &mut self,
 12        view: &mut V,
 13        cx: &mut LayoutContext<V>,
 14    ) -> Result<(LayoutId, Self::PaintState)>
 15    where
 16        Self: Sized;
 17
 18    fn paint(
 19        &mut self,
 20        view: &mut V,
 21        layout: &Layout,
 22        state: &mut Self::PaintState,
 23        cx: &mut PaintContext<V>,
 24    ) where
 25        Self: Sized;
 26
 27    fn into_any(self) -> AnyElement<V>
 28    where
 29        Self: 'static + Sized,
 30    {
 31        AnyElement(Box::new(StatefulElement {
 32            element: self,
 33            phase: ElementPhase::Init,
 34        }))
 35    }
 36}
 37
 38/// Used to make ElementState<V, E> into a trait object, so we can wrap it in AnyElement<V>.
 39trait AnyStatefulElement<V> {
 40    fn layout(&mut self, view: &mut V, cx: &mut LayoutContext<V>) -> Result<LayoutId>;
 41    fn paint(&mut self, view: &mut V, cx: &mut PaintContext<V>);
 42}
 43
 44/// A wrapper around an element that stores its layout state.
 45struct StatefulElement<V: 'static, E: Element<V>> {
 46    element: E,
 47    phase: ElementPhase<V, E>,
 48}
 49
 50enum ElementPhase<V: 'static, E: Element<V>> {
 51    Init,
 52    PostLayout {
 53        layout_id: LayoutId,
 54        paint_state: E::PaintState,
 55    },
 56    PostPaint {
 57        layout: Layout,
 58        paint_state: E::PaintState,
 59    },
 60    Error(String),
 61}
 62
 63impl<V: 'static, E: Element<V>> Default for ElementPhase<V, E> {
 64    fn default() -> Self {
 65        Self::Init
 66    }
 67}
 68
 69/// We blanket-implement the object-safe ElementStateObject interface to make ElementStates into trait objects
 70impl<V, E: Element<V>> AnyStatefulElement<V> for StatefulElement<V, E> {
 71    fn layout(&mut self, view: &mut V, cx: &mut LayoutContext<V>) -> Result<LayoutId> {
 72        let result;
 73        self.phase = match std::mem::take(&mut self.phase) {
 74            ElementPhase::Init => match self.element.layout(view, cx) {
 75                Ok((layout_id, paint_state)) => {
 76                    result = Ok(layout_id);
 77                    ElementPhase::PostLayout {
 78                        layout_id,
 79                        paint_state,
 80                    }
 81                }
 82                Err(error) => {
 83                    let message = error.to_string();
 84                    result = Err(error);
 85                    ElementPhase::Error(message)
 86                }
 87            },
 88            _ => panic!("invalid element phase to call layout"),
 89        };
 90
 91        result
 92    }
 93
 94    fn paint(&mut self, view: &mut V, cx: &mut PaintContext<V>) {
 95        self.phase = match std::mem::take(&mut self.phase) {
 96            ElementPhase::PostLayout {
 97                layout_id,
 98                mut paint_state,
 99            } => match cx.computed_layout(layout_id) {
100                Ok(layout) => {
101                    self.element.paint(view, &layout, &mut paint_state, cx);
102                    ElementPhase::PostPaint {
103                        layout,
104                        paint_state,
105                    }
106                }
107                Err(error) => ElementPhase::Error(error.to_string()),
108            },
109            phase @ ElementPhase::Error(_) => phase,
110            _ => panic!("invalid element phase to call paint"),
111        };
112    }
113}
114
115/// A dynamic element.
116pub struct AnyElement<V>(Box<dyn AnyStatefulElement<V>>);
117
118impl<V> AnyElement<V> {
119    pub fn layout(&mut self, view: &mut V, cx: &mut LayoutContext<V>) -> Result<LayoutId> {
120        self.0.layout(view, cx)
121    }
122
123    pub fn paint(&mut self, view: &mut V, cx: &mut PaintContext<V>) {
124        self.0.paint(view, cx)
125    }
126}
127
128pub trait ParentElement<V: 'static> {
129    fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<V>; 2]>;
130
131    fn child(mut self, child: impl IntoElement<V>) -> Self
132    where
133        Self: Sized,
134    {
135        self.children_mut().push(child.into_element().into_any());
136        self
137    }
138
139    fn children<I, E>(mut self, children: I) -> Self
140    where
141        I: IntoIterator<Item = E>,
142        E: IntoElement<V>,
143        Self: Sized,
144    {
145        self.children_mut().extend(
146            children
147                .into_iter()
148                .map(|child| child.into_element().into_any()),
149        );
150        self
151    }
152}
153
154pub trait IntoElement<V: 'static> {
155    type Element: Element<V>;
156
157    fn into_element(self) -> Self::Element;
158}