use crate::{ private::Sealed, AnyBox, AnyElement, AnyModel, AnyWeakModel, AppContext, AvailableSpace, 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}, }; 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(AnyView::from(self)) } } pub struct WeakView { pub(crate) model: WeakModel, } impl WeakView { pub fn entity_id(&self) -> EntityId { self.model.entity_id } 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 {} #[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: any_view::initialize::, layout: any_view::layout::, paint: any_view::paint::, } } } 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 From> for AnyWeakView { fn from(view: WeakView) -> Self { Self { model: view.model.into(), initialize: any_view::initialize::, layout: any_view::layout::, paint: any_view::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) } } mod any_view { use crate::{AnyElement, AnyView, BorrowWindow, LayoutId, Render, WindowContext}; use std::any::Any; pub(crate) fn initialize(view: &AnyView, cx: &mut WindowContext) -> Box { cx.with_element_id(Some(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) }) } pub(crate) fn layout( view: &AnyView, element: &mut Box, cx: &mut WindowContext, ) -> LayoutId { cx.with_element_id(Some(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)) }) } pub(crate) fn paint( view: &AnyView, element: &mut Box, cx: &mut WindowContext, ) { cx.with_element_id(Some(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)) }) } }