view.rs

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