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