use anyhow::Result; use derive_more::{Deref, DerefMut}; use gpui::geometry::rect::RectF; use gpui::EngineLayout; use std::marker::PhantomData; use util::ResultExt; use crate::layout_context::LayoutContext; use crate::paint_context::PaintContext; type LayoutId = gpui::LayoutId; #[derive(Deref, DerefMut)] pub struct Layout { id: LayoutId, engine_layout: Option, #[deref] #[deref_mut] element_data: D, view_type: PhantomData, } impl Layout { pub fn new(id: LayoutId, engine_layout: Option, element_data: D) -> Self { Self { id, engine_layout, element_data, view_type: PhantomData, } } pub fn bounds(&mut self, cx: &mut PaintContext) -> RectF { self.engine_layout(cx).bounds } pub fn order(&mut self, cx: &mut PaintContext) -> u32 { self.engine_layout(cx).order } fn engine_layout(&mut self, cx: &mut PaintContext<'_, '_, '_, '_, V>) -> &mut EngineLayout { self.engine_layout .get_or_insert_with(|| cx.computed_layout(self.id).log_err().unwrap_or_default()) } } pub trait Element: 'static { type Layout; fn layout( &mut self, view: &mut V, cx: &mut LayoutContext, ) -> Result> where Self: Sized; fn paint( &mut self, view: &mut V, layout: &mut Layout, cx: &mut PaintContext, ) where Self: Sized; fn into_any(self) -> AnyElement where Self: 'static + Sized, { AnyElement(Box::new(ElementState { element: self, layout: None, })) } } /// Used to make ElementState into a trait object, so we can wrap it in AnyElement. trait ElementStateObject { fn layout(&mut self, view: &mut V, cx: &mut LayoutContext) -> Result; fn paint(&mut self, view: &mut V, layout_id: LayoutId, cx: &mut PaintContext); } /// A wrapper around an element that stores its layout state. struct ElementState> { element: E, layout: Option>, } /// We blanket-implement the object-safe ElementStateObject interface to make ElementStates into trait objects impl> ElementStateObject for ElementState { fn layout(&mut self, view: &mut V, cx: &mut LayoutContext) -> Result { let layout = self.element.layout(view, cx)?; let layout_id = layout.id; self.layout = Some(layout); Ok(layout_id) } fn paint(&mut self, view: &mut V, layout_id: LayoutId, cx: &mut PaintContext) { let layout = self.layout.as_mut().expect("paint called before layout"); self.element.paint(view, layout, cx) } } /// A dynamic element. pub struct AnyElement(Box>); impl AnyElement { pub fn layout(&mut self, view: &mut V, cx: &mut LayoutContext) -> Result { self.0.layout(view, cx) } pub fn paint(&mut self, view: &mut V, layout_id: LayoutId, cx: &mut PaintContext) { self.0.paint(view, layout_id, cx) } } pub trait ParentElement { fn children_mut(&mut self) -> &mut Vec>; fn child(mut self, child: impl IntoElement) -> Self where Self: Sized, { self.children_mut().push(child.into_element().into_any()); self } fn children(mut self, children: I) -> Self where I: IntoIterator, E: IntoElement, Self: Sized, { self.children_mut().extend( children .into_iter() .map(|child| child.into_element().into_any()), ); self } } pub trait IntoElement { type Element: Element; fn into_element(self) -> Self::Element; }