use super::{Layout, LayoutId, Pixels, Point, Result, ViewContext}; pub(crate) use smallvec::SmallVec; pub trait Element: 'static { type State; type FrameState; fn layout( &mut self, state: &mut Self::State, cx: &mut ViewContext, ) -> Result<(LayoutId, Self::FrameState)>; fn paint( &mut self, layout: Layout, state: &mut Self::State, frame_state: &mut Self::FrameState, cx: &mut ViewContext, ) -> Result<()>; } pub trait ParentElement { 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 } } 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 { layout: Layout, 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 layout = cx.layout(layout_id)?.clone(); offset.map(|offset| layout.bounds.origin += offset); self.element .paint(layout.clone(), state, &mut frame_state, cx)?; ElementRenderPhase::Painted { layout, frame_state, } } ElementRenderPhase::Painted { layout, mut frame_state, } => { self.element .paint(layout.clone(), state, &mut frame_state, cx)?; ElementRenderPhase::Painted { layout, 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 } }