use crate::{BorrowWindow, Bounds, ElementId, LayoutId, Pixels, ViewContext}; use derive_more::{Deref, DerefMut}; pub(crate) use smallvec::SmallVec; use std::{any::Any, mem}; pub trait Element { type ElementState: 'static; fn id(&self) -> Option; /// Called to initialize this element for the current frame. If this /// element had state in a previous frame, it will be passed in for the 3rd argument. fn initialize( &mut self, view_state: &mut V, element_state: Option, cx: &mut ViewContext, ) -> Self::ElementState; fn layout( &mut self, view_state: &mut V, element_state: &mut Self::ElementState, cx: &mut ViewContext, ) -> LayoutId; fn paint( &mut self, bounds: Bounds, view_state: &mut V, 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 { fn children_mut(&mut self) -> &mut SmallVec<[AnyElement; 2]>; fn child(mut self, child: impl Component) -> Self where Self: Sized, { self.children_mut().push(child.render()); self } fn children(mut self, iter: impl IntoIterator>) -> Self where Self: Sized, { self.children_mut() .extend(iter.into_iter().map(|item| item.render())); self } } trait ElementObject { 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, E::ElementState: 'static, { fn initialize(&mut self, view_state: &mut V, 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 V, 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 V, 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 where V: 'static, E: 'static + Element, E::ElementState: Any, { 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 Component { fn render(self) -> AnyElement; fn when(mut self, condition: bool, then: impl FnOnce(Self) -> Self) -> Self where Self: Sized, { if condition { self = then(self); } self } } impl Component for AnyElement { fn render(self) -> AnyElement { self } } impl Element for Option where V: 'static, E: 'static + Component, F: FnOnce(&mut V, &mut ViewContext<'_, V>) -> E + 'static, { type ElementState = AnyElement; fn id(&self) -> Option { None } fn initialize( &mut self, view_state: &mut V, _rendered_element: Option, cx: &mut ViewContext, ) -> Self::ElementState { let render = self.take().unwrap(); let mut rendered_element = (render)(view_state, cx).render(); rendered_element.initialize(view_state, cx); rendered_element } fn layout( &mut self, view_state: &mut V, rendered_element: &mut Self::ElementState, cx: &mut ViewContext, ) -> LayoutId { rendered_element.layout(view_state, cx) } fn paint( &mut self, _bounds: Bounds, view_state: &mut V, rendered_element: &mut Self::ElementState, cx: &mut ViewContext, ) { rendered_element.paint(view_state, cx) } } impl Component for Option where V: 'static, E: 'static + Component, F: FnOnce(&mut V, &mut ViewContext<'_, V>) -> E + 'static, { fn render(self) -> AnyElement { AnyElement::new(self) } } impl Component for F where V: 'static, E: 'static + Component, F: FnOnce(&mut V, &mut ViewContext<'_, V>) -> E + 'static, { fn render(self) -> AnyElement { AnyElement::new(Some(self)) } }