use crate::{ private::Sealed, AnyBox, AnyElement, AnyModel, AnyWeakModel, AppContext, AvailableSpace, BorrowWindow, Bounds, Component, Element, ElementId, Entity, EntityId, Flatten, LayoutId, Model, Pixels, Size, ViewContext, VisualContext, WeakModel, WindowContext, }; use anyhow::{Context, Result}; use std::{ any::{Any, TypeId}, hash::{Hash, Hasher}, marker::PhantomData, }; pub trait Render: 'static + Sized { type Element: Element + 'static; fn render(&mut self, cx: &mut ViewContext) -> Self::Element; } pub struct View { pub(crate) model: Model, } impl Sealed for View {} impl Entity for View { type Weak = WeakView; fn entity_id(&self) -> EntityId { self.model.entity_id } fn downgrade(&self) -> Self::Weak { WeakView { model: self.model.downgrade(), } } fn upgrade_from(weak: &Self::Weak) -> Option where Self: Sized, { let model = weak.model.upgrade()?; Some(View { model }) } } impl View { /// Convert this strong view reference into a weak view reference. pub fn downgrade(&self) -> WeakView { Entity::downgrade(self) } pub fn update( &self, cx: &mut C, f: impl FnOnce(&mut V, &mut ViewContext<'_, V>) -> R, ) -> C::Result where C: VisualContext, { cx.update_view(self, f) } pub fn read<'a>(&self, cx: &'a AppContext) -> &'a V { self.model.read(cx) } } impl Clone for View { fn clone(&self) -> Self { Self { model: self.model.clone(), } } } impl Hash for View { fn hash(&self, state: &mut H) { self.model.hash(state); } } impl PartialEq for View { fn eq(&self, other: &Self) -> bool { self.model == other.model } } impl Eq for View {} impl Component for View { fn render(self) -> AnyElement { AnyElement::new(EraseViewState { view: self, parent_view_state_type: PhantomData, }) } } impl Element<()> for View where V: Render, { type ElementState = AnyElement; fn id(&self) -> Option { Some(ElementId::View(self.model.entity_id)) } fn initialize( &mut self, _: &mut (), _: Option, cx: &mut ViewContext<()>, ) -> Self::ElementState { self.update(cx, |state, cx| { let mut any_element = AnyElement::new(state.render(cx)); any_element.initialize(state, cx); any_element }) } fn layout( &mut self, _: &mut (), element: &mut Self::ElementState, cx: &mut ViewContext<()>, ) -> LayoutId { self.update(cx, |state, cx| element.layout(state, cx)) } fn paint( &mut self, _: Bounds, _: &mut (), element: &mut Self::ElementState, cx: &mut ViewContext<()>, ) { self.update(cx, |state, cx| element.paint(state, cx)) } } pub struct WeakView { pub(crate) model: WeakModel, } impl WeakView { pub fn upgrade(&self) -> Option> { Entity::upgrade_from(self) } pub fn update( &self, cx: &mut C, f: impl FnOnce(&mut V, &mut ViewContext<'_, V>) -> R, ) -> Result where C: VisualContext, Result>: Flatten, { let view = self.upgrade().context("error upgrading view")?; Ok(view.update(cx, f)).flatten() } } impl Clone for WeakView { fn clone(&self) -> Self { Self { model: self.model.clone(), } } } impl Hash for WeakView { fn hash(&self, state: &mut H) { self.model.hash(state); } } impl PartialEq for WeakView { fn eq(&self, other: &Self) -> bool { self.model == other.model } } impl Eq for WeakView {} struct EraseViewState { view: View, parent_view_state_type: PhantomData, } unsafe impl Send for EraseViewState {} impl Component for EraseViewState { fn render(self) -> AnyElement { AnyElement::new(self) } } impl Element for EraseViewState { type ElementState = Box; fn id(&self) -> Option { Element::id(&self.view) } fn initialize( &mut self, _: &mut ParentV, _: Option, cx: &mut ViewContext, ) -> Self::ElementState { ViewObject::initialize(&mut self.view, cx) } fn layout( &mut self, _: &mut ParentV, element: &mut Self::ElementState, cx: &mut ViewContext, ) -> LayoutId { ViewObject::layout(&mut self.view, element, cx) } fn paint( &mut self, bounds: Bounds, _: &mut ParentV, element: &mut Self::ElementState, cx: &mut ViewContext, ) { ViewObject::paint(&mut self.view, bounds, element, cx) } } trait ViewObject: Send + Sync { fn entity_type(&self) -> TypeId; fn entity_id(&self) -> EntityId; fn model(&self) -> AnyModel; fn initialize(&self, cx: &mut WindowContext) -> AnyBox; fn layout(&self, element: &mut AnyBox, cx: &mut WindowContext) -> LayoutId; fn paint(&self, bounds: Bounds, element: &mut AnyBox, cx: &mut WindowContext); fn debug(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result; } impl ViewObject for View where V: Render, { fn entity_type(&self) -> TypeId { TypeId::of::() } fn entity_id(&self) -> EntityId { Entity::entity_id(self) } fn model(&self) -> AnyModel { self.model.clone().into_any() } fn initialize(&self, cx: &mut WindowContext) -> AnyBox { cx.with_element_id(ViewObject::entity_id(self), |_global_id, cx| { self.update(cx, |state, cx| { let mut any_element = Box::new(AnyElement::new(state.render(cx))); any_element.initialize(state, cx); any_element }) }) } fn layout(&self, element: &mut AnyBox, cx: &mut WindowContext) -> LayoutId { cx.with_element_id(ViewObject::entity_id(self), |_global_id, cx| { self.update(cx, |state, cx| { let element = element.downcast_mut::>().unwrap(); element.layout(state, cx) }) }) } fn paint(&self, _: Bounds, element: &mut AnyBox, cx: &mut WindowContext) { cx.with_element_id(ViewObject::entity_id(self), |_global_id, cx| { self.update(cx, |state, cx| { let element = element.downcast_mut::>().unwrap(); element.paint(state, cx); }); }); } fn debug(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct(&format!("AnyView<{}>", std::any::type_name::())) .field("entity_id", &ViewObject::entity_id(self).as_u64()) .finish() } } #[derive(Clone, Debug)] pub struct AnyView { model: AnyModel, initialize: fn(&AnyView, &mut WindowContext) -> AnyBox, layout: fn(&AnyView, &mut AnyBox, &mut WindowContext) -> LayoutId, paint: fn(&AnyView, &mut AnyBox, &mut WindowContext), } impl AnyView { pub fn downgrade(&self) -> AnyWeakView { AnyWeakView { model: self.model.downgrade(), initialize: self.initialize, layout: self.layout, paint: self.paint, } } pub fn downcast(self) -> Result, Self> { match self.model.downcast() { Ok(model) => Ok(View { model }), Err(model) => Err(Self { model, initialize: self.initialize, layout: self.layout, paint: self.paint, }), } } pub fn entity_type(&self) -> TypeId { self.model.entity_type } pub(crate) fn draw(&self, available_space: Size, cx: &mut WindowContext) { let mut rendered_element = (self.initialize)(self, cx); let layout_id = (self.layout)(self, &mut rendered_element, cx); cx.window .layout_engine .compute_layout(layout_id, available_space); (self.paint)(self, &mut rendered_element, cx); } } impl Component for AnyView { fn render(self) -> AnyElement { AnyElement::new(self) } } impl From> for AnyView { fn from(value: View) -> Self { AnyView { model: value.model.into_any(), initialize: |view, cx| { cx.with_element_id(view.model.entity_id, |_, cx| { let view = view.clone().downcast::().unwrap(); let element = view.update(cx, |view, cx| { let mut element = AnyElement::new(view.render(cx)); element.initialize(view, cx); element }); Box::new(element) }) }, layout: |view, element, cx| { cx.with_element_id(view.model.entity_id, |_, cx| { let view = view.clone().downcast::().unwrap(); let element = element.downcast_mut::>().unwrap(); view.update(cx, |view, cx| element.layout(view, cx)) }) }, paint: |view, element, cx| { cx.with_element_id(view.model.entity_id, |_, cx| { let view = view.clone().downcast::().unwrap(); let element = element.downcast_mut::>().unwrap(); view.update(cx, |view, cx| element.paint(view, cx)) }) }, } } } impl Element for AnyView { type ElementState = Box; fn id(&self) -> Option { Some(self.model.entity_id.into()) } fn initialize( &mut self, _view_state: &mut ParentViewState, _element_state: Option, cx: &mut ViewContext, ) -> Self::ElementState { (self.initialize)(self, cx) } fn layout( &mut self, _view_state: &mut ParentViewState, rendered_element: &mut Self::ElementState, cx: &mut ViewContext, ) -> LayoutId { (self.layout)(self, rendered_element, cx) } fn paint( &mut self, _bounds: Bounds, _view_state: &mut ParentViewState, rendered_element: &mut Self::ElementState, cx: &mut ViewContext, ) { (self.paint)(self, rendered_element, cx) } } pub struct AnyWeakView { model: AnyWeakModel, initialize: fn(&AnyView, &mut WindowContext) -> AnyBox, layout: fn(&AnyView, &mut AnyBox, &mut WindowContext) -> LayoutId, paint: fn(&AnyView, &mut AnyBox, &mut WindowContext), } impl AnyWeakView { pub fn upgrade(&self) -> Option { let model = self.model.upgrade()?; Some(AnyView { model, initialize: self.initialize, layout: self.layout, paint: self.paint, }) } } impl Render for T where T: 'static + FnMut(&mut WindowContext) -> E, E: 'static + Send + Element, { type Element = E; fn render(&mut self, cx: &mut ViewContext) -> Self::Element { (self)(cx) } }