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        dbg!("Layout view");
 63        self.state.update(cx, |state, cx| {
 64            let mut element = (self.render)(state, cx);
 65            let layout_id = element.layout(state, cx)?;
 66            Ok((layout_id, element))
 67        })
 68    }
 69
 70    fn paint(
 71        &mut self,
 72        _: Layout,
 73        _: &mut Self::State,
 74        element: &mut Self::FrameState,
 75        cx: &mut ViewContext<Self::State>,
 76    ) -> Result<()> {
 77        dbg!("Paint view");
 78        self.state
 79            .update(cx, |state, cx| element.paint(state, None, cx))
 80    }
 81}
 82
 83trait ViewObject: Send + 'static {
 84    fn layout(&mut self, cx: &mut WindowContext) -> Result<(LayoutId, Box<dyn Any>)>;
 85    fn paint(
 86        &mut self,
 87        layout: Layout,
 88        element: &mut dyn Any,
 89        cx: &mut WindowContext,
 90    ) -> Result<()>;
 91}
 92
 93impl<S: Send + Sync + 'static, P: Send + 'static> ViewObject for View<S, P> {
 94    fn layout(&mut self, cx: &mut WindowContext) -> Result<(LayoutId, Box<dyn Any>)> {
 95        self.state.update(cx, |state, cx| {
 96            let mut element = (self.render)(state, cx);
 97            let layout_id = element.layout(state, cx)?;
 98            let element = Box::new(element) as Box<dyn Any>;
 99            Ok((layout_id, element))
100        })
101    }
102
103    fn paint(&mut self, _: Layout, element: &mut dyn Any, cx: &mut WindowContext) -> Result<()> {
104        self.state.update(cx, |state, cx| {
105            let boxed_element = element.downcast_mut::<Box<dyn Any>>().unwrap();
106            let element = boxed_element.downcast_mut::<AnyElement<S>>().unwrap();
107
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        layout: Layout,
133        _: &mut Self::State,
134        element: &mut Self::FrameState,
135        cx: &mut ViewContext<Self::State>,
136    ) -> Result<()> {
137        dbg!("Element.paint for AnyView");
138        self.view.lock().paint(layout, element, cx)
139    }
140}
141
142impl<S> Clone for AnyView<S> {
143    fn clone(&self) -> Self {
144        Self {
145            view: self.view.clone(),
146            parent_state_type: PhantomData,
147        }
148    }
149}