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::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 Element for View { type State = Option; fn layout( &mut self, _state: Option, cx: &mut WindowContext, ) -> (LayoutId, Self::State) { let mut element = self.update(cx, |view, cx| view.render(cx).into_any()); let layout_id = element.layout(cx); (layout_id, Some(element)) } fn paint(self, _: Bounds, element: &mut Self::State, cx: &mut WindowContext) { element.take().unwrap().paint(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, AnyElement), paint: fn(&AnyView, AnyElement, &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 Element for AnyView { type State = Option; fn layout( &mut self, _state: Option, cx: &mut WindowContext, ) -> (LayoutId, Self::State) { let (layout_id, state) = (self.layout)(self, cx); (layout_id, Some(state)) } fn paint(self, _: Bounds, state: &mut Self::State, cx: &mut WindowContext) { (self.paint)(&self, state.take().unwrap(), cx) } } impl 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 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, AnyElement), paint: fn(&AnyView, AnyElement, &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::, } } } 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, Element, LayoutId, Render, WindowContext}; pub(crate) fn layout( view: &AnyView, cx: &mut WindowContext, ) -> (LayoutId, AnyElement) { cx.with_element_id(Some(view.model.entity_id), |cx| { let view = view.clone().downcast::().unwrap(); let mut element = view.update(cx, |view, cx| view.render(cx).into_any()); let layout_id = element.layout(cx); (layout_id, element) }) } pub(crate) fn paint( view: &AnyView, element: AnyElement, cx: &mut WindowContext, ) { cx.with_element_id(Some(view.model.entity_id), |cx| { element.paint(cx); }) } }