use crate::{Bounds, Identified, LayoutId, Pixels, Point, Result, ViewContext}; use derive_more::{Deref, DerefMut}; pub(crate) use smallvec::SmallVec; use util::arc_cow::ArcCow; pub trait Element: 'static { type State; type FrameState; fn element_id(&self) -> Option { None } fn layout( &mut self, state: &mut Self::State, cx: &mut ViewContext, ) -> Result<(LayoutId, Self::FrameState)>; fn paint( &mut self, bounds: Bounds, state: &mut Self::State, frame_state: &mut Self::FrameState, cx: &mut ViewContext, ) -> Result<()>; fn id(self, id: ElementId) -> Identified where Self: Sized, { Identified { element: self, id } } } pub trait StatefulElement: Element { fn element_id(&self) -> ElementId { Element::element_id(self).unwrap() } } #[derive(Clone, Debug, Eq, PartialEq, Hash)] pub struct ElementId(ArcCow<'static, [u8]>); #[derive(Deref, DerefMut, Default, Clone, Debug)] pub(crate) struct GlobalElementId(SmallVec<[ElementId; 8]>); pub trait ParentElement { type State; fn children_mut(&mut self) -> &mut SmallVec<[AnyElement; 2]>; fn child(mut self, child: impl IntoAnyElement) -> Self where Self: Sized, { self.children_mut().push(child.into_any()); self } fn children(mut self, iter: impl IntoIterator>) -> Self where Self: Sized, { self.children_mut() .extend(iter.into_iter().map(|item| item.into_any())); self } // HACK: This is a temporary hack to get children working for the purposes // of building UI on top of the current version of gpui2. // // We'll (hopefully) be moving away from this in the future. fn children_any(mut self, children: I) -> Self where I: IntoIterator>, Self: Sized, { self.children_mut().extend(children.into_iter()); self } // HACK: This is a temporary hack to get children working for the purposes // of building UI on top of the current version of gpui2. // // We'll (hopefully) be moving away from this in the future. fn child_any(mut self, children: AnyElement) -> Self where Self: Sized, { self.children_mut().push(children); self } } trait ElementObject { fn layout(&mut self, state: &mut S, cx: &mut ViewContext) -> Result; fn paint( &mut self, state: &mut S, offset: Option>, cx: &mut ViewContext, ) -> Result<()>; } struct RenderedElement { element: E, phase: ElementRenderPhase, } #[derive(Default)] enum ElementRenderPhase { #[default] Rendered, LayoutRequested { layout_id: LayoutId, frame_state: S, }, Painted { bounds: Bounds, frame_state: S, }, } /// Internal struct that wraps an element to store Layout and FrameState after the element is rendered. /// It's allocated as a trait object to erase the element type and wrapped in AnyElement for /// improved usability. impl RenderedElement { fn new(element: E) -> Self { RenderedElement { element, phase: ElementRenderPhase::Rendered, } } } impl ElementObject for RenderedElement { fn layout(&mut self, state: &mut E::State, cx: &mut ViewContext) -> Result { let (layout_id, frame_state) = self.element.layout(state, cx)?; self.phase = ElementRenderPhase::LayoutRequested { layout_id, frame_state, }; Ok(layout_id) } fn paint( &mut self, state: &mut E::State, offset: Option>, cx: &mut ViewContext, ) -> Result<()> { self.phase = match std::mem::take(&mut self.phase) { ElementRenderPhase::Rendered => panic!("must call layout before paint"), ElementRenderPhase::LayoutRequested { layout_id, mut frame_state, } => { let mut bounds = cx.layout_bounds(layout_id)?.clone(); offset.map(|offset| bounds.origin += offset); self.element.paint(bounds, state, &mut frame_state, cx)?; ElementRenderPhase::Painted { bounds, frame_state, } } ElementRenderPhase::Painted { bounds, mut frame_state, } => { self.element .paint(bounds.clone(), state, &mut frame_state, cx)?; ElementRenderPhase::Painted { bounds, frame_state, } } }; Ok(()) } } pub struct AnyElement(Box>); impl AnyElement { pub fn layout(&mut self, state: &mut S, cx: &mut ViewContext) -> Result { self.0.layout(state, cx) } pub fn paint( &mut self, state: &mut S, offset: Option>, cx: &mut ViewContext, ) -> Result<()> { self.0.paint(state, offset, cx) } } pub trait IntoAnyElement { fn into_any(self) -> AnyElement; } impl IntoAnyElement for E { fn into_any(self) -> AnyElement { AnyElement(Box::new(RenderedElement::new(self))) } } impl IntoAnyElement for AnyElement { fn into_any(self) -> AnyElement { self } }