view.rs

  1use crate::{
  2    AnyElement, Element, Handle, IntoAnyElement, Layout, LayoutId, Result, ViewContext,
  3    WindowContext,
  4};
  5use std::{any::Any, cell::RefCell, marker::PhantomData, rc::Rc, sync::Arc};
  6
  7pub struct View<S, P> {
  8    state: Handle<S>,
  9    render: Arc<dyn Fn(&mut S, &mut ViewContext<S>) -> AnyElement<S> + Send + Sync + 'static>,
 10    parent_state_type: PhantomData<P>,
 11}
 12
 13impl<S, P> Clone for View<S, P> {
 14    fn clone(&self) -> Self {
 15        Self {
 16            state: self.state.clone(),
 17            render: self.render.clone(),
 18            parent_state_type: PhantomData,
 19        }
 20    }
 21}
 22
 23pub type RootView<S> = View<S, ()>;
 24
 25pub fn view<S: 'static, P: 'static, E: Element<State = S>>(
 26    state: Handle<S>,
 27    render: impl Fn(&mut S, &mut ViewContext<S>) -> E + Send + Sync + 'static,
 28) -> View<S, P> {
 29    View {
 30        state,
 31        render: Arc::new(move |state, cx| render(state, cx).into_any()),
 32        parent_state_type: PhantomData,
 33    }
 34}
 35
 36impl<S: Send + 'static, P: 'static> View<S, P> {
 37    pub fn into_any<ParentState>(self) -> AnyView<ParentState> {
 38        AnyView {
 39            view: Rc::new(RefCell::new(self)),
 40            parent_state_type: PhantomData,
 41        }
 42    }
 43}
 44
 45impl<S: Send + 'static, P: Send + 'static> Element for View<S, P> {
 46    type State = P;
 47    type FrameState = AnyElement<S>;
 48
 49    fn layout(
 50        &mut self,
 51        _: &mut Self::State,
 52        cx: &mut ViewContext<Self::State>,
 53    ) -> Result<(LayoutId, Self::FrameState)> {
 54        self.state.update(cx, |state, cx| {
 55            let mut element = (self.render)(state, cx);
 56            let layout_id = element.layout(state, cx)?;
 57            Ok((layout_id, element))
 58        })
 59    }
 60
 61    fn paint(
 62        &mut self,
 63        layout: Layout,
 64        _: &mut Self::State,
 65        element: &mut Self::FrameState,
 66        cx: &mut ViewContext<Self::State>,
 67    ) -> Result<()> {
 68        self.state
 69            .update(cx, |state, cx| element.paint(state, None, cx))
 70    }
 71}
 72
 73trait ViewObject {
 74    fn layout(&mut self, cx: &mut WindowContext) -> Result<(LayoutId, Box<dyn Any>)>;
 75    fn paint(
 76        &mut self,
 77        layout: Layout,
 78        element: &mut dyn Any,
 79        cx: &mut WindowContext,
 80    ) -> Result<()>;
 81}
 82
 83impl<S: Send + 'static, P> ViewObject for View<S, P> {
 84    fn layout(&mut self, cx: &mut WindowContext) -> Result<(LayoutId, Box<dyn Any>)> {
 85        self.state.update(cx, |state, cx| {
 86            let mut element = (self.render)(state, cx);
 87            let layout_id = element.layout(state, cx)?;
 88            let element = Box::new(element) as Box<dyn Any>;
 89            Ok((layout_id, element))
 90        })
 91    }
 92
 93    fn paint(
 94        &mut self,
 95        layout: Layout,
 96        element: &mut dyn Any,
 97        cx: &mut WindowContext,
 98    ) -> Result<()> {
 99        self.state.update(cx, |state, cx| {
100            element
101                .downcast_mut::<AnyElement<S>>()
102                .unwrap()
103                .paint(state, None, cx)
104        })
105    }
106}
107
108pub struct AnyView<S> {
109    view: Rc<RefCell<dyn ViewObject>>,
110    parent_state_type: PhantomData<S>,
111}
112
113impl<S: 'static> Element for AnyView<S> {
114    type State = S;
115    type FrameState = Box<dyn Any>;
116
117    fn layout(
118        &mut self,
119        _: &mut Self::State,
120        cx: &mut ViewContext<Self::State>,
121    ) -> Result<(LayoutId, Self::FrameState)> {
122        self.view.borrow_mut().layout(cx)
123    }
124
125    fn paint(
126        &mut self,
127        layout: Layout,
128        _: &mut Self::State,
129        element: &mut Self::FrameState,
130        cx: &mut ViewContext<Self::State>,
131    ) -> Result<()> {
132        self.view.borrow_mut().paint(layout, element, cx)
133    }
134}
135
136impl<S> Clone for AnyView<S> {
137    fn clone(&self) -> Self {
138        Self {
139            view: self.view.clone(),
140            parent_state_type: PhantomData,
141        }
142    }
143}