view.rs

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