use crate::{ private::Sealed, AnyElement, AnyModel, AnyWeakModel, AppContext, AvailableSpace, BorrowWindow, Bounds, Element, ElementId, Entity, EntityId, Flatten, FocusHandle, FocusableView, LayoutId, Model, Pixels, Point, Render, RenderOnce, Size, ViewContext, VisualContext, WeakModel, WindowContext, }; use anyhow::{Context, Result}; use std::{ any::{Any, TypeId}, hash::{Hash, Hasher}, }; pub struct View { pub 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) } pub fn render_with(&self, component: E) -> RenderViewWith where E: 'static + Element, { RenderViewWith { view: self.clone(), element: Some(component), } } pub fn focus_handle(&self, cx: &AppContext) -> FocusHandle where V: FocusableView, { self.read(cx).focus_handle(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 {} 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, layout: fn(&AnyView, &mut WindowContext) -> (LayoutId, Box), paint: fn(&AnyView, Box, &mut WindowContext), } impl AnyView { pub fn downgrade(&self) -> AnyWeakView { AnyWeakView { model: self.model.downgrade(), 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, layout: self.layout, paint: self.paint, }), } } pub fn entity_type(&self) -> TypeId { self.model.entity_type } pub fn entity_id(&self) -> EntityId { self.model.entity_id() } pub(crate) fn draw( &self, origin: Point, available_space: Size, cx: &mut WindowContext, ) { cx.with_absolute_element_offset(origin, |cx| { let (layout_id, rendered_element) = (self.layout)(self, cx); cx.window .layout_engine .compute_layout(layout_id, available_space); (self.paint)(self, rendered_element, cx); }) } } impl> From> for AnyView { fn from(value: View) -> Self { AnyView { model: value.model.into_any(), layout: any_view::layout::, paint: any_view::paint::, } } } impl, ParentV: 'static> Element for View { type State = Option>; fn layout( &mut self, _parent_view: &mut ParentV, _state: Option, cx: &mut ViewContext, ) -> (LayoutId, Self::State) { self.update(cx, |view, cx| { let mut element = view.render(cx).into_any(); let layout_id = element.layout(view, cx); (layout_id, Some(element)) }) } fn paint( self, _: Bounds, _parent: &mut ParentV, element: &mut Self::State, cx: &mut ViewContext, ) { self.update(cx, |view, cx| { element.take().unwrap().paint(view, cx); }); } } impl, ParentV: 'static> RenderOnce for View { type Element = View; fn element_id(&self) -> Option { Some(self.model.entity_id.into()) } fn render_once(self) -> Self::Element { self } } impl Element for AnyView { type State = Option>; fn layout( &mut self, _view_state: &mut V, _element_state: Option, cx: &mut ViewContext, ) -> (LayoutId, Self::State) { let (layout_id, rendered_element) = (self.layout)(self, cx); (layout_id, Some(rendered_element)) } fn paint( mut self, _bounds: Bounds, _view_state: &mut V, rendered_element: &mut Self::State, cx: &mut ViewContext, ) { (self.paint)(&mut self, rendered_element.take().unwrap(), cx) } } impl RenderOnce for AnyView { type Element = Self; fn element_id(&self) -> Option { Some(self.model.entity_id.into()) } fn render_once(self) -> Self::Element { self } } pub struct AnyWeakView { model: AnyWeakModel, layout: fn(&AnyView, &mut WindowContext) -> (LayoutId, Box), paint: fn(&AnyView, Box, &mut WindowContext), } impl AnyWeakView { pub fn upgrade(&self) -> Option { let model = self.model.upgrade()?; Some(AnyView { model, layout: self.layout, paint: self.paint, }) } } impl> From> for AnyWeakView { fn from(view: WeakView) -> Self { Self { model: view.model.into(), layout: any_view::layout::, paint: any_view::paint::, } } } pub struct RenderViewWith { view: View, element: Option, } impl Element for RenderViewWith where E: 'static + Element, ParentV: 'static, V: 'static, { type State = Option>; fn layout( &mut self, _: &mut ParentV, _: Option, cx: &mut ViewContext, ) -> (LayoutId, Self::State) { self.view.update(cx, |view, cx| { let mut element = self.element.take().unwrap().into_any(); let layout_id = element.layout(view, cx); (layout_id, Some(element)) }) } fn paint( self, _: Bounds, _: &mut ParentV, element: &mut Self::State, cx: &mut ViewContext, ) { self.view .update(cx, |view, cx| element.take().unwrap().paint(view, cx)) } } impl RenderOnce for RenderViewWith where E: 'static + Element, V: 'static, ParentV: 'static, { type Element = Self; fn element_id(&self) -> Option { self.element.as_ref().unwrap().element_id() } fn render_once(self) -> Self::Element { self } } mod any_view { use crate::{AnyElement, AnyView, BorrowWindow, LayoutId, Render, WindowContext}; use std::any::Any; pub(crate) fn layout>( view: &AnyView, cx: &mut WindowContext, ) -> (LayoutId, Box) { cx.with_element_id(Some(view.model.entity_id), |cx| { let view = view.clone().downcast::().unwrap(); view.update(cx, |view, cx| { let mut element = AnyElement::new(view.render(cx)); let layout_id = element.layout(view, cx); (layout_id, Box::new(element) as Box) }) }) } pub(crate) fn paint>( view: &AnyView, element: Box, cx: &mut WindowContext, ) { cx.with_element_id(Some(view.model.entity_id), |cx| { let view = view.clone().downcast::().unwrap(); let element = element.downcast::>().unwrap(); view.update(cx, |view, cx| element.paint(view, cx)) }) } }