use parking_lot::Mutex; use crate::{ AnyBox, AnyElement, BorrowWindow, Bounds, Element, ElementId, EntityId, Handle, IntoAnyElement, LayoutId, Pixels, ViewContext, WindowContext, }; use std::{marker::PhantomData, sync::Arc}; pub struct View { state: Handle, render: Arc) -> AnyElement + Send + Sync + 'static>, } impl View { pub fn into_any(self) -> AnyView { AnyView { view: Arc::new(Mutex::new(self)), } } } impl Clone for View { fn clone(&self) -> Self { Self { state: self.state.clone(), render: self.render.clone(), } } } pub fn view( state: Handle, render: impl Fn(&mut V, &mut ViewContext) -> E + Send + Sync + 'static, ) -> View where E: IntoAnyElement, V: 'static + Send + Sync, { View { state, render: Arc::new(move |state, cx| render(state, cx).into_any()), } } impl IntoAnyElement for View { fn into_any(self) -> AnyElement { AnyElement::new(EraseViewState { view: self, parent_view_state_type: PhantomData, }) } } impl Element for View { type ViewState = (); type ElementState = AnyElement; fn id(&self) -> Option { Some(ElementId::View(self.state.id)) } fn initialize( &mut self, _: &mut (), _: Option, cx: &mut ViewContext<()>, ) -> Self::ElementState { self.state.update(cx, |state, cx| { let mut any_element = (self.render)(state, cx); any_element.initialize(state, cx); any_element }) } fn layout( &mut self, _: &mut (), element: &mut Self::ElementState, cx: &mut ViewContext<()>, ) -> LayoutId { self.state.update(cx, |state, cx| element.layout(state, cx)) } fn paint( &mut self, _: Bounds, _: &mut (), element: &mut Self::ElementState, cx: &mut ViewContext<()>, ) { self.state.update(cx, |state, cx| element.paint(state, cx)) } } struct EraseViewState { view: View, parent_view_state_type: PhantomData, } impl IntoAnyElement for EraseViewState where V: 'static + Send + Sync, ParentV: 'static + Send + Sync, { fn into_any(self) -> AnyElement { AnyElement::new(self) } } impl Element for EraseViewState where V: 'static + Send + Sync, ParentV: 'static + Send + Sync, { type ViewState = ParentV; type ElementState = AnyBox; fn id(&self) -> Option { Element::id(&self.view) } fn initialize( &mut self, _: &mut Self::ViewState, _: Option, cx: &mut ViewContext, ) -> Self::ElementState { ViewObject::initialize(&mut self.view, cx) } fn layout( &mut self, _: &mut Self::ViewState, element: &mut Self::ElementState, cx: &mut ViewContext, ) -> LayoutId { ViewObject::layout(&mut self.view, element, cx) } fn paint( &mut self, bounds: Bounds, _: &mut Self::ViewState, element: &mut Self::ElementState, cx: &mut ViewContext, ) { ViewObject::paint(&mut self.view, bounds, element, cx) } } trait ViewObject: 'static + Send + Sync { fn entity_id(&self) -> EntityId; fn initialize(&mut self, cx: &mut WindowContext) -> AnyBox; fn layout(&mut self, element: &mut AnyBox, cx: &mut WindowContext) -> LayoutId; fn paint(&mut self, bounds: Bounds, element: &mut AnyBox, cx: &mut WindowContext); } impl ViewObject for View { fn entity_id(&self) -> EntityId { self.state.id } fn initialize(&mut self, cx: &mut WindowContext) -> AnyBox { cx.with_element_id(self.entity_id(), |_global_id, cx| { self.state.update(cx, |state, cx| { let mut any_element = Box::new((self.render)(state, cx)); any_element.initialize(state, cx); any_element as AnyBox }) }) } fn layout(&mut self, element: &mut AnyBox, cx: &mut WindowContext) -> LayoutId { cx.with_element_id(self.entity_id(), |_global_id, cx| { self.state.update(cx, |state, cx| { let element = element.downcast_mut::>().unwrap(); element.layout(state, cx) }) }) } fn paint(&mut self, _: Bounds, element: &mut AnyBox, cx: &mut WindowContext) { cx.with_element_id(self.entity_id(), |_global_id, cx| { self.state.update(cx, |state, cx| { let element = element.downcast_mut::>().unwrap(); element.paint(state, cx); }); }); } } pub struct AnyView { view: Arc>, } impl IntoAnyElement for AnyView where ParentV: 'static + Send + Sync, { fn into_any(self) -> AnyElement { AnyElement::new(EraseAnyViewState { view: self, parent_view_state_type: PhantomData, }) } } impl Element for AnyView { type ViewState = (); type ElementState = AnyBox; fn id(&self) -> Option { Some(ElementId::View(self.view.lock().entity_id())) } fn initialize( &mut self, _: &mut Self::ViewState, _: Option, cx: &mut ViewContext, ) -> Self::ElementState { self.view.lock().initialize(cx) } fn layout( &mut self, _: &mut Self::ViewState, element: &mut Self::ElementState, cx: &mut ViewContext, ) -> LayoutId { self.view.lock().layout(element, cx) } fn paint( &mut self, bounds: Bounds, _: &mut (), element: &mut AnyBox, cx: &mut ViewContext, ) { self.view.lock().paint(bounds, element, cx) } } struct EraseAnyViewState { view: AnyView, parent_view_state_type: PhantomData, } impl IntoAnyElement for EraseAnyViewState where ParentV: 'static + Send + Sync, { fn into_any(self) -> AnyElement { AnyElement::new(self) } } impl Element for EraseAnyViewState where ParentV: 'static + Send + Sync, { type ViewState = ParentV; type ElementState = AnyBox; fn id(&self) -> Option { Element::id(&self.view) } fn initialize( &mut self, _: &mut Self::ViewState, _: Option, cx: &mut ViewContext, ) -> Self::ElementState { self.view.view.lock().initialize(cx) } fn layout( &mut self, _: &mut Self::ViewState, element: &mut Self::ElementState, cx: &mut ViewContext, ) -> LayoutId { self.view.view.lock().layout(element, cx) } fn paint( &mut self, bounds: Bounds, _: &mut Self::ViewState, element: &mut Self::ElementState, cx: &mut ViewContext, ) { self.view.view.lock().paint(bounds, element, cx) } } impl Clone for AnyView { fn clone(&self) -> Self { Self { view: self.view.clone(), } } }