use crate::{BorrowWindow, Bounds, ElementId, Identified, LayoutId, Pixels, Point, ViewContext}; use derive_more::{Deref, DerefMut}; pub(crate) use smallvec::SmallVec; pub trait Element: 'static + Send + Sync { type ViewState: 'static + Send + Sync; type ElementState: 'static + Send + Sync; fn element_id(&self) -> Option { None } fn layout( &mut self, state: &mut Self::ViewState, element_state: Option, cx: &mut ViewContext, ) -> (LayoutId, Self::ElementState); fn paint( &mut self, bounds: Bounds, state: &mut Self::ViewState, element_state: &mut Self::ElementState, cx: &mut ViewContext, ); fn id(self, id: impl Into) -> Identified where Self: Sized, { Identified { element: self, id: id.into(), } } } pub trait StatefulElement: Element { fn element_id(&self) -> ElementId { Element::element_id(self).unwrap() } } #[derive(Deref, DerefMut, Default, Clone, Debug, Eq, PartialEq, Hash)] 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 } } trait ElementObject: 'static + Send + Sync { fn layout(&mut self, state: &mut S, cx: &mut ViewContext) -> LayoutId; fn paint(&mut self, state: &mut S, offset: Option>, cx: &mut ViewContext); } struct RenderedElement { element: E, phase: ElementRenderPhase, } #[derive(Default)] enum ElementRenderPhase { #[default] Rendered, LayoutRequested { layout_id: LayoutId, frame_state: Option, }, Painted { bounds: Bounds, frame_state: Option, }, } /// 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::Rendered, } } fn paint_with_element_state( &mut self, bounds: Bounds, view_state: &mut E::ViewState, frame_state: &mut Option, cx: &mut ViewContext, ) { if let Some(id) = self.element.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); } } } impl ElementObject for RenderedElement where E: Element, S: 'static + Send + Sync, { fn layout(&mut self, state: &mut E::ViewState, cx: &mut ViewContext) -> LayoutId { let (layout_id, frame_state) = if let Some(id) = self.element.element_id() { let layout_id = cx.with_element_state(id, |element_state, cx| { self.element.layout(state, element_state, cx) }); (layout_id, None) } else { let (layout_id, frame_state) = self.element.layout(state, None, cx); (layout_id, Some(frame_state)) }; self.phase = ElementRenderPhase::LayoutRequested { layout_id, frame_state, }; layout_id } fn paint( &mut self, view_state: &mut E::ViewState, offset: Option>, cx: &mut ViewContext, ) { 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); offset.map(|offset| bounds.origin += offset); self.paint_with_element_state(bounds, view_state, &mut frame_state, cx); ElementRenderPhase::Painted { bounds, frame_state, } } ElementRenderPhase::Painted { bounds, mut frame_state, } => { self.paint_with_element_state(bounds, view_state, &mut frame_state, cx); ElementRenderPhase::Painted { bounds, frame_state, } } }; } } pub struct AnyElement(Box>); impl AnyElement { pub fn layout(&mut self, state: &mut S, cx: &mut ViewContext) -> LayoutId { self.0.layout(state, cx) } pub fn paint(&mut self, state: &mut S, offset: Option>, cx: &mut ViewContext) { 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 } }