view.rs

  1use parking_lot::Mutex;
  2
  3use crate::{
  4    AnyBox, AnyElement, BorrowWindow, Bounds, Element, ElementId, Handle, IdentifiedElement,
  5    IntoAnyElement, LayoutId, Pixels, ViewContext, 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 + Sync> 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<ViewState = 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: 'static + Send + Sync, P: 'static + Send + Sync> Element for View<S, P> {
 53    type ViewState = P;
 54    type ElementState = AnyElement<S>;
 55
 56    fn element_id(&self) -> Option<crate::ElementId> {
 57        Some(ElementId::View(self.state.id))
 58    }
 59
 60    fn layout(
 61        &mut self,
 62        _: &mut Self::ViewState,
 63        _: Option<Self::ElementState>,
 64        cx: &mut ViewContext<Self::ViewState>,
 65    ) -> (LayoutId, Self::ElementState) {
 66        self.state.update(cx, |state, cx| {
 67            let mut element = (self.render)(state, cx);
 68            let layout_id = element.layout(state, cx);
 69            (layout_id, element)
 70        })
 71    }
 72
 73    fn paint(
 74        &mut self,
 75        _: Bounds<Pixels>,
 76        _: &mut Self::ViewState,
 77        element: &mut Self::ElementState,
 78        cx: &mut ViewContext<Self::ViewState>,
 79    ) {
 80        self.state
 81            .update(cx, |state, cx| element.paint(state, None, cx))
 82    }
 83}
 84
 85trait ViewObject: Send + 'static {
 86    fn layout(&mut self, cx: &mut WindowContext) -> (LayoutId, AnyBox);
 87    fn paint(&mut self, bounds: Bounds<Pixels>, element: &mut dyn Any, cx: &mut WindowContext);
 88}
 89
 90impl<S: Send + Sync + 'static, P: Send + Sync + 'static> IdentifiedElement for View<S, P> {}
 91
 92impl<S: Send + Sync + 'static, P: Send + Sync + 'static> ViewObject for View<S, P> {
 93    fn layout(&mut self, cx: &mut WindowContext) -> (LayoutId, AnyBox) {
 94        cx.with_element_id(IdentifiedElement::element_id(self), |cx| {
 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 AnyBox;
 99                (layout_id, element)
100            })
101        })
102    }
103
104    fn paint(&mut self, _: Bounds<Pixels>, element: &mut dyn Any, cx: &mut WindowContext) {
105        cx.with_element_id(IdentifiedElement::element_id(self), |cx| {
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}
113
114pub struct AnyView<S> {
115    view: Arc<Mutex<dyn ViewObject>>,
116    parent_state_type: PhantomData<S>,
117}
118
119impl<S: 'static + Send + Sync> Element for AnyView<S> {
120    type ViewState = ();
121    type ElementState = AnyBox;
122
123    fn element_id(&self) -> Option<crate::ElementId> {
124        None
125    }
126
127    fn layout(
128        &mut self,
129        _: &mut Self::ViewState,
130        _: Option<Self::ElementState>,
131        cx: &mut ViewContext<Self::ViewState>,
132    ) -> (LayoutId, Self::ElementState) {
133        self.view.lock().layout(cx)
134    }
135
136    fn paint(
137        &mut self,
138        bounds: Bounds<Pixels>,
139        _: &mut (),
140        element: &mut AnyBox,
141        cx: &mut ViewContext<Self::ViewState>,
142    ) {
143        self.view.lock().paint(bounds, element.as_mut(), cx)
144    }
145}
146
147impl<S> Clone for AnyView<S> {
148    fn clone(&self) -> Self {
149        Self {
150            view: self.view.clone(),
151            parent_state_type: PhantomData,
152        }
153    }
154}