view.rs

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