element.rs

  1use anyhow::Result;
  2use derive_more::{Deref, DerefMut};
  3use gpui::{geometry::rect::RectF, EngineLayout};
  4use smallvec::SmallVec;
  5use std::marker::PhantomData;
  6use util::ResultExt;
  7
  8pub use crate::layout_context::LayoutContext;
  9pub use crate::paint_context::PaintContext;
 10
 11type LayoutId = gpui::LayoutId;
 12
 13pub trait Element<V: 'static>: 'static {
 14    type Layout;
 15
 16    fn layout(
 17        &mut self,
 18        view: &mut V,
 19        cx: &mut LayoutContext<V>,
 20    ) -> Result<Layout<V, Self::Layout>>
 21    where
 22        Self: Sized;
 23
 24    fn paint(
 25        &mut self,
 26        view: &mut V,
 27        layout: &mut Layout<V, Self::Layout>,
 28        cx: &mut PaintContext<V>,
 29    ) where
 30        Self: Sized;
 31
 32    fn into_any(self) -> AnyElement<V>
 33    where
 34        Self: 'static + Sized,
 35    {
 36        AnyElement(Box::new(ElementState {
 37            element: self,
 38            layout: None,
 39        }))
 40    }
 41}
 42
 43/// Used to make ElementState<V, E> into a trait object, so we can wrap it in AnyElement<V>.
 44trait ElementStateObject<V> {
 45    fn layout(&mut self, view: &mut V, cx: &mut LayoutContext<V>) -> Result<LayoutId>;
 46    fn paint(&mut self, view: &mut V, cx: &mut PaintContext<V>);
 47}
 48
 49/// A wrapper around an element that stores its layout state.
 50struct ElementState<V: 'static, E: Element<V>> {
 51    element: E,
 52    layout: Option<Layout<V, E::Layout>>,
 53}
 54
 55/// We blanket-implement the object-safe ElementStateObject interface to make ElementStates into trait objects
 56impl<V, E: Element<V>> ElementStateObject<V> for ElementState<V, E> {
 57    fn layout(&mut self, view: &mut V, cx: &mut LayoutContext<V>) -> Result<LayoutId> {
 58        let layout = self.element.layout(view, cx)?;
 59        let layout_id = layout.id;
 60        self.layout = Some(layout);
 61        Ok(layout_id)
 62    }
 63
 64    fn paint(&mut self, view: &mut V, cx: &mut PaintContext<V>) {
 65        let layout = self.layout.as_mut().expect("paint called before layout");
 66        if layout.engine_layout.is_none() {
 67            layout.engine_layout = cx.computed_layout(layout.id).log_err()
 68        }
 69        self.element.paint(view, layout, cx)
 70    }
 71}
 72
 73/// A dynamic element.
 74pub struct AnyElement<V>(Box<dyn ElementStateObject<V>>);
 75
 76impl<V> AnyElement<V> {
 77    pub fn layout(&mut self, view: &mut V, cx: &mut LayoutContext<V>) -> Result<LayoutId> {
 78        self.0.layout(view, cx)
 79    }
 80
 81    pub fn paint(&mut self, view: &mut V, cx: &mut PaintContext<V>) {
 82        self.0.paint(view, cx)
 83    }
 84}
 85
 86#[derive(Deref, DerefMut)]
 87pub struct Layout<V, D> {
 88    id: LayoutId,
 89    engine_layout: Option<EngineLayout>,
 90    #[deref]
 91    #[deref_mut]
 92    element_data: D,
 93    view_type: PhantomData<V>,
 94}
 95
 96impl<V: 'static, D> Layout<V, D> {
 97    pub fn new(id: LayoutId, element_data: D) -> Self {
 98        Self {
 99            id,
100            engine_layout: None,
101            element_data: element_data,
102            view_type: PhantomData,
103        }
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    fn engine_layout(&mut self, cx: &mut PaintContext<'_, '_, '_, '_, V>) -> &mut EngineLayout {
115        self.engine_layout
116            .get_or_insert_with(|| cx.computed_layout(self.id).log_err().unwrap_or_default())
117    }
118}
119
120impl<V: 'static> Layout<V, Option<AnyElement<V>>> {
121    pub fn paint(&mut self, view: &mut V, cx: &mut PaintContext<V>) {
122        let mut element = self.element_data.take().unwrap();
123        element.paint(view, cx);
124        self.element_data = Some(element);
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}