element.rs

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