use crate::{BorrowWindow, Bounds, ElementId, LayoutId, Pixels, ViewContext}; use derive_more::{Deref, DerefMut}; pub(crate) use smallvec::SmallVec; use std::mem; pub trait Element: 'static + Send + Sync + IntoAnyElement { type ViewState: 'static + Send + Sync; type ElementState: 'static + Send + Sync; fn id(&self) -> Option; fn initialize( &mut self, view_state: &mut Self::ViewState, element_state: Option, cx: &mut ViewContext, ) -> Self::ElementState; fn layout( &mut self, view_state: &mut Self::ViewState, element_state: &mut Self::ElementState, cx: &mut ViewContext, ) -> LayoutId; fn paint( &mut self, bounds: Bounds, view_state: &mut Self::ViewState, element_state: &mut Self::ElementState, cx: &mut ViewContext, ); } #[derive(Deref, DerefMut, Default, Clone, Debug, Eq, PartialEq, Hash)] pub struct GlobalElementId(SmallVec<[ElementId; 32]>); pub trait ParentElement: Element { 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: 'static + Send + Sync { fn initialize(&mut self, view_state: &mut V, cx: &mut ViewContext); fn layout(&mut self, view_state: &mut V, cx: &mut ViewContext) -> LayoutId; fn paint(&mut self, view_state: &mut V, cx: &mut ViewContext); } struct RenderedElement { element: E, phase: ElementRenderPhase, } #[derive(Default)] enum ElementRenderPhase { #[default] Start, Initialized { frame_state: Option, }, LayoutRequested { layout_id: LayoutId, frame_state: Option, }, Painted, } /// Internal struct that wraps an element to store Layout and ElementState 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::Start, } } } impl ElementObject for RenderedElement where E: Element, { fn initialize(&mut self, view_state: &mut E::ViewState, cx: &mut ViewContext) { let frame_state = if let Some(id) = self.element.id() { cx.with_element_state(id, |element_state, cx| { let element_state = self.element.initialize(view_state, element_state, cx); ((), element_state) }); None } else { let frame_state = self.element.initialize(view_state, None, cx); Some(frame_state) }; self.phase = ElementRenderPhase::Initialized { frame_state }; } fn layout(&mut self, state: &mut E::ViewState, cx: &mut ViewContext) -> LayoutId { let layout_id; let mut frame_state; match mem::take(&mut self.phase) { ElementRenderPhase::Initialized { frame_state: initial_frame_state, } => { frame_state = initial_frame_state; if let Some(id) = self.element.id() { layout_id = cx.with_element_state(id, |element_state, cx| { let mut element_state = element_state.unwrap(); let layout_id = self.element.layout(state, &mut element_state, cx); (layout_id, element_state) }); } else { layout_id = self .element .layout(state, frame_state.as_mut().unwrap(), cx); } } _ => panic!("must call initialize before layout"), }; self.phase = ElementRenderPhase::LayoutRequested { layout_id, frame_state, }; layout_id } fn paint(&mut self, view_state: &mut E::ViewState, cx: &mut ViewContext) { self.phase = match mem::take(&mut self.phase) { ElementRenderPhase::LayoutRequested { layout_id, mut frame_state, } => { let bounds = cx.layout_bounds(layout_id); if let Some(id) = self.element.id() { cx.with_element_state(id, |element_state, cx| { let mut element_state = element_state.unwrap(); self.element .paint(bounds, view_state, &mut element_state, cx); ((), element_state) }); } else { self.element .paint(bounds, view_state, frame_state.as_mut().unwrap(), cx); } ElementRenderPhase::Painted } _ => panic!("must call layout before paint"), }; } } pub struct AnyElement(Box>); impl AnyElement { pub fn new>(element: E) -> Self { AnyElement(Box::new(RenderedElement::new(element))) } pub fn initialize(&mut self, view_state: &mut V, cx: &mut ViewContext) { self.0.initialize(view_state, cx); } pub fn layout(&mut self, view_state: &mut V, cx: &mut ViewContext) -> LayoutId { self.0.layout(view_state, cx) } pub fn paint(&mut self, view_state: &mut V, cx: &mut ViewContext) { self.0.paint(view_state, cx) } } pub trait IntoAnyElement { fn into_any(self) -> AnyElement; } impl IntoAnyElement for AnyElement { fn into_any(self) -> AnyElement { self } }