use crate::{ private::Sealed, AnyElement, AnyModel, AnyWeakModel, AppContext, AvailableSpace, BorrowWindow, Bounds, Element, ElementId, Entity, EntityId, Flatten, FocusHandle, FocusableView, IntoElement, LayoutId, Model, Pixels, Point, Render, Size, ViewContext, VisualContext, WeakModel, WindowContext, }; use anyhow::{Context, Result}; use std::{ any::TypeId, fmt, 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 request_layout( &mut self, _state: Option, cx: &mut WindowContext, ) -> (LayoutId, Self::State) { let mut element = self.update(cx, |view, cx| view.render(cx).into_any_element()); let layout_id = element.request_layout(cx); (layout_id, Some(element)) } fn paint(&mut 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() } #[cfg(any(test, feature = "test-support"))] pub fn assert_dropped(&self) { self.model.assert_dropped() } } 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, &mut 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, mut rendered_element) = (self.layout)(self, cx); cx.compute_layout(layout_id, available_space); (self.paint)(self, &mut 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 request_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(&mut self, _: Bounds, state: &mut Self::State, cx: &mut WindowContext) { debug_assert!( state.is_some(), "state is None. Did you include an AnyView twice in the tree?" ); (self.paint)(self, state.as_mut().unwrap(), cx) } } impl IntoElement for View { type Element = View; fn element_id(&self) -> Option { Some(ElementId::from_entity_id(self.model.entity_id)) } fn into_element(self) -> Self::Element { self } } impl IntoElement for AnyView { type Element = Self; fn element_id(&self) -> Option { Some(ElementId::from_entity_id(self.model.entity_id)) } fn into_element(self) -> Self::Element { self } } pub struct AnyWeakView { model: AnyWeakModel, layout: fn(&AnyView, &mut WindowContext) -> (LayoutId, AnyElement), paint: fn(&AnyView, &mut 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 PartialEq for AnyWeakView { fn eq(&self, other: &Self) -> bool { self.model == other.model } } impl std::fmt::Debug for AnyWeakView { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("AnyWeakView") .field("entity_id", &self.model.entity_id) .finish_non_exhaustive() } } mod any_view { use crate::{AnyElement, AnyView, IntoElement, LayoutId, Render, WindowContext}; pub(crate) fn layout( view: &AnyView, cx: &mut WindowContext, ) -> (LayoutId, AnyElement) { let view = view.clone().downcast::().unwrap(); let mut element = view.update(cx, |view, cx| view.render(cx).into_any_element()); let layout_id = element.request_layout(cx); (layout_id, element) } pub(crate) fn paint(_view: &AnyView, element: &mut AnyElement, cx: &mut WindowContext) { element.paint(cx); } }