element.rs

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