view.rs

  1use parking_lot::Mutex;
  2
  3use crate::{
  4    AnyBox, AnyElement, BorrowWindow, Bounds, Element, ElementId, EntityId, Handle, IntoAnyElement,
  5    LayoutId, Pixels, ViewContext, WindowContext,
  6};
  7use std::{marker::PhantomData, sync::Arc};
  8
  9pub struct View<S: Send + Sync> {
 10    state: Handle<S>,
 11    render: Arc<dyn Fn(&mut S, &mut ViewContext<S>) -> AnyElement<S> + Send + Sync + 'static>,
 12}
 13
 14impl<S: 'static + Send + Sync> View<S> {
 15    pub fn into_any(self) -> AnyView {
 16        AnyView {
 17            view: Arc::new(Mutex::new(self)),
 18        }
 19    }
 20}
 21
 22impl<S: Send + Sync> Clone for View<S> {
 23    fn clone(&self) -> Self {
 24        Self {
 25            state: self.state.clone(),
 26            render: self.render.clone(),
 27        }
 28    }
 29}
 30
 31pub fn view<S, E>(
 32    state: Handle<S>,
 33    render: impl Fn(&mut S, &mut ViewContext<S>) -> E + Send + Sync + 'static,
 34) -> View<S>
 35where
 36    E: IntoAnyElement<S>,
 37    S: 'static + Send + Sync,
 38{
 39    View {
 40        state,
 41        render: Arc::new(move |state, cx| render(state, cx).into_any()),
 42    }
 43}
 44
 45impl<S: 'static + Send + Sync, ParentViewState: 'static + Send + Sync>
 46    IntoAnyElement<ParentViewState> for View<S>
 47{
 48    fn into_any(self) -> AnyElement<ParentViewState> {
 49        AnyElement::new(EraseViewState {
 50            view: self,
 51            parent_view_state_type: PhantomData,
 52        })
 53    }
 54}
 55
 56impl<S: 'static + Send + Sync> Element for View<S> {
 57    type ViewState = ();
 58    type ElementState = AnyElement<S>;
 59
 60    fn id(&self) -> Option<crate::ElementId> {
 61        Some(ElementId::View(self.state.id))
 62    }
 63
 64    fn layout(
 65        &mut self,
 66        _: &mut Self::ViewState,
 67        _: Option<Self::ElementState>,
 68        cx: &mut ViewContext<Self::ViewState>,
 69    ) -> (LayoutId, Self::ElementState) {
 70        self.state.update(cx, |state, cx| {
 71            let mut element = (self.render)(state, cx);
 72            let layout_id = element.layout(state, cx);
 73            (layout_id, element)
 74        })
 75    }
 76
 77    fn paint(
 78        &mut self,
 79        _: Bounds<Pixels>,
 80        _: &mut Self::ViewState,
 81        element: &mut Self::ElementState,
 82        cx: &mut ViewContext<Self::ViewState>,
 83    ) {
 84        self.state
 85            .update(cx, |state, cx| element.paint(state, None, cx))
 86    }
 87}
 88
 89struct EraseViewState<ViewState: 'static + Send + Sync, ParentViewState> {
 90    view: View<ViewState>,
 91    parent_view_state_type: PhantomData<ParentViewState>,
 92}
 93
 94impl<ViewState, ParentViewState> IntoAnyElement<ParentViewState>
 95    for EraseViewState<ViewState, ParentViewState>
 96where
 97    ViewState: 'static + Send + Sync,
 98    ParentViewState: 'static + Send + Sync,
 99{
100    fn into_any(self) -> AnyElement<ParentViewState> {
101        AnyElement::new(self)
102    }
103}
104
105impl<ViewState, ParentViewState> Element for EraseViewState<ViewState, ParentViewState>
106where
107    ViewState: 'static + Send + Sync,
108    ParentViewState: 'static + Send + Sync,
109{
110    type ViewState = ParentViewState;
111    type ElementState = AnyBox;
112
113    fn id(&self) -> Option<crate::ElementId> {
114        Element::id(&self.view)
115    }
116
117    fn layout(
118        &mut self,
119        _: &mut Self::ViewState,
120        _: Option<Self::ElementState>,
121        cx: &mut ViewContext<Self::ViewState>,
122    ) -> (LayoutId, Self::ElementState) {
123        ViewObject::layout(&mut self.view, cx)
124    }
125
126    fn paint(
127        &mut self,
128        bounds: Bounds<Pixels>,
129        _: &mut Self::ViewState,
130        element: &mut Self::ElementState,
131        cx: &mut ViewContext<Self::ViewState>,
132    ) {
133        ViewObject::paint(&mut self.view, bounds, element, cx)
134    }
135}
136
137trait ViewObject: 'static + Send + Sync {
138    fn entity_id(&self) -> EntityId;
139    fn layout(&mut self, cx: &mut WindowContext) -> (LayoutId, AnyBox);
140    fn paint(&mut self, bounds: Bounds<Pixels>, element: &mut AnyBox, cx: &mut WindowContext);
141}
142
143impl<S: Send + Sync + 'static> ViewObject for View<S> {
144    fn entity_id(&self) -> EntityId {
145        self.state.id
146    }
147
148    fn layout(&mut self, cx: &mut WindowContext) -> (LayoutId, AnyBox) {
149        cx.with_element_id(self.entity_id(), |cx| {
150            self.state.update(cx, |state, cx| {
151                let mut element = (self.render)(state, cx);
152                let layout_id = element.layout(state, cx);
153                let element = Box::new(element) as AnyBox;
154                (layout_id, element)
155            })
156        })
157    }
158
159    fn paint(&mut self, _: Bounds<Pixels>, element: &mut AnyBox, cx: &mut WindowContext) {
160        cx.with_element_id(self.entity_id(), |cx| {
161            self.state.update(cx, |state, cx| {
162                let element = element.downcast_mut::<AnyElement<S>>().unwrap();
163                element.paint(state, None, cx);
164            });
165        });
166    }
167}
168
169pub struct AnyView {
170    view: Arc<Mutex<dyn ViewObject>>,
171}
172
173impl<ParentViewState> IntoAnyElement<ParentViewState> for AnyView
174where
175    ParentViewState: 'static + Send + Sync,
176{
177    fn into_any(self) -> AnyElement<ParentViewState> {
178        AnyElement::new(EraseAnyViewState {
179            view: self,
180            parent_view_state_type: PhantomData,
181        })
182    }
183}
184
185impl Element for AnyView {
186    type ViewState = ();
187    type ElementState = AnyBox;
188
189    fn id(&self) -> Option<crate::ElementId> {
190        Some(ElementId::View(self.view.lock().entity_id()))
191    }
192
193    fn layout(
194        &mut self,
195        _: &mut Self::ViewState,
196        _: Option<Self::ElementState>,
197        cx: &mut ViewContext<Self::ViewState>,
198    ) -> (LayoutId, Self::ElementState) {
199        self.view.lock().layout(cx)
200    }
201
202    fn paint(
203        &mut self,
204        bounds: Bounds<Pixels>,
205        _: &mut (),
206        element: &mut AnyBox,
207        cx: &mut ViewContext<Self::ViewState>,
208    ) {
209        self.view.lock().paint(bounds, element, cx)
210    }
211}
212
213struct EraseAnyViewState<ParentViewState> {
214    view: AnyView,
215    parent_view_state_type: PhantomData<ParentViewState>,
216}
217
218impl<ParentViewState> IntoAnyElement<ParentViewState> for EraseAnyViewState<ParentViewState>
219where
220    ParentViewState: 'static + Send + Sync,
221{
222    fn into_any(self) -> AnyElement<ParentViewState> {
223        AnyElement::new(self)
224    }
225}
226
227impl<ParentViewState> Element for EraseAnyViewState<ParentViewState>
228where
229    ParentViewState: 'static + Send + Sync,
230{
231    type ViewState = ParentViewState;
232    type ElementState = AnyBox;
233
234    fn id(&self) -> Option<crate::ElementId> {
235        Element::id(&self.view)
236    }
237
238    fn layout(
239        &mut self,
240        _: &mut Self::ViewState,
241        _: Option<Self::ElementState>,
242        cx: &mut ViewContext<Self::ViewState>,
243    ) -> (LayoutId, Self::ElementState) {
244        self.view.view.lock().layout(cx)
245    }
246
247    fn paint(
248        &mut self,
249        bounds: Bounds<Pixels>,
250        _: &mut Self::ViewState,
251        element: &mut Self::ElementState,
252        cx: &mut ViewContext<Self::ViewState>,
253    ) {
254        self.view.view.lock().paint(bounds, element, cx)
255    }
256}
257
258impl Clone for AnyView {
259    fn clone(&self) -> Self {
260        Self {
261            view: self.view.clone(),
262        }
263    }
264}