view.rs

  1use crate::{
  2    private::Sealed, AnyBox, AnyElement, AnyModel, AnyWeakModel, AppContext, AvailableSpace,
  3    BorrowWindow, Bounds, Component, Element, ElementId, Entity, EntityId, LayoutId, Model, Pixels,
  4    Size, ViewContext, VisualContext, WeakModel, WindowContext,
  5};
  6use anyhow::{Context, Result};
  7use std::{
  8    any::{Any, TypeId},
  9    marker::PhantomData,
 10};
 11
 12pub trait Render: 'static + Sized {
 13    type Element: Element<Self> + 'static;
 14
 15    fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element;
 16}
 17
 18pub struct View<V> {
 19    pub(crate) model: Model<V>,
 20}
 21
 22impl<V> Sealed for View<V> {}
 23
 24impl<V: 'static> Entity<V> for View<V> {
 25    type Weak = WeakView<V>;
 26
 27    fn entity_id(&self) -> EntityId {
 28        self.model.entity_id
 29    }
 30
 31    fn downgrade(&self) -> Self::Weak {
 32        WeakView {
 33            model: self.model.downgrade(),
 34        }
 35    }
 36
 37    fn upgrade_from(weak: &Self::Weak) -> Option<Self>
 38    where
 39        Self: Sized,
 40    {
 41        let model = weak.model.upgrade()?;
 42        Some(View { model })
 43    }
 44}
 45
 46impl<V: 'static> View<V> {
 47    /// Convert this strong view reference into a weak view reference.
 48    pub fn downgrade(&self) -> WeakView<V> {
 49        Entity::downgrade(self)
 50    }
 51
 52    pub fn update<C, R>(
 53        &self,
 54        cx: &mut C,
 55        f: impl FnOnce(&mut V, &mut C::ViewContext<'_, '_, V>) -> R,
 56    ) -> C::Result<R>
 57    where
 58        C: VisualContext,
 59    {
 60        cx.update_view(self, f)
 61    }
 62
 63    pub fn read<'a>(&self, cx: &'a AppContext) -> &'a V {
 64        self.model.read(cx)
 65    }
 66}
 67
 68impl<V> Clone for View<V> {
 69    fn clone(&self) -> Self {
 70        Self {
 71            model: self.model.clone(),
 72        }
 73    }
 74}
 75
 76impl<V: Render, ParentViewState: 'static> Component<ParentViewState> for View<V> {
 77    fn render(self) -> AnyElement<ParentViewState> {
 78        AnyElement::new(EraseViewState {
 79            view: self,
 80            parent_view_state_type: PhantomData,
 81        })
 82    }
 83}
 84
 85impl<V> Element<()> for View<V>
 86where
 87    V: Render,
 88{
 89    type ElementState = AnyElement<V>;
 90
 91    fn id(&self) -> Option<crate::ElementId> {
 92        Some(ElementId::View(self.model.entity_id))
 93    }
 94
 95    fn initialize(
 96        &mut self,
 97        _: &mut (),
 98        _: Option<Self::ElementState>,
 99        cx: &mut ViewContext<()>,
100    ) -> Self::ElementState {
101        self.update(cx, |state, cx| {
102            let mut any_element = AnyElement::new(state.render(cx));
103            any_element.initialize(state, cx);
104            any_element
105        })
106    }
107
108    fn layout(
109        &mut self,
110        _: &mut (),
111        element: &mut Self::ElementState,
112        cx: &mut ViewContext<()>,
113    ) -> LayoutId {
114        self.update(cx, |state, cx| element.layout(state, cx))
115    }
116
117    fn paint(
118        &mut self,
119        _: Bounds<Pixels>,
120        _: &mut (),
121        element: &mut Self::ElementState,
122        cx: &mut ViewContext<()>,
123    ) {
124        self.update(cx, |state, cx| element.paint(state, cx))
125    }
126}
127
128pub struct WeakView<V> {
129    pub(crate) model: WeakModel<V>,
130}
131
132impl<V: 'static> WeakView<V> {
133    pub fn upgrade(&self) -> Option<View<V>> {
134        Entity::upgrade_from(self)
135    }
136
137    pub fn update<R>(
138        &self,
139        cx: &mut WindowContext,
140        f: impl FnOnce(&mut V, &mut ViewContext<V>) -> R,
141    ) -> Result<R> {
142        let view = self.upgrade().context("error upgrading view")?;
143        Ok(view.update(cx, f))
144    }
145}
146
147impl<V> Clone for WeakView<V> {
148    fn clone(&self) -> Self {
149        Self {
150            model: self.model.clone(),
151        }
152    }
153}
154
155struct EraseViewState<V, ParentV> {
156    view: View<V>,
157    parent_view_state_type: PhantomData<ParentV>,
158}
159
160unsafe impl<V, ParentV> Send for EraseViewState<V, ParentV> {}
161
162impl<V: Render, ParentV: 'static> Component<ParentV> for EraseViewState<V, ParentV> {
163    fn render(self) -> AnyElement<ParentV> {
164        AnyElement::new(self)
165    }
166}
167
168impl<V: Render, ParentV: 'static> Element<ParentV> for EraseViewState<V, ParentV> {
169    type ElementState = Box<dyn Any>;
170
171    fn id(&self) -> Option<crate::ElementId> {
172        Element::id(&self.view)
173    }
174
175    fn initialize(
176        &mut self,
177        _: &mut ParentV,
178        _: Option<Self::ElementState>,
179        cx: &mut ViewContext<ParentV>,
180    ) -> Self::ElementState {
181        ViewObject::initialize(&mut self.view, cx)
182    }
183
184    fn layout(
185        &mut self,
186        _: &mut ParentV,
187        element: &mut Self::ElementState,
188        cx: &mut ViewContext<ParentV>,
189    ) -> LayoutId {
190        ViewObject::layout(&mut self.view, element, cx)
191    }
192
193    fn paint(
194        &mut self,
195        bounds: Bounds<Pixels>,
196        _: &mut ParentV,
197        element: &mut Self::ElementState,
198        cx: &mut ViewContext<ParentV>,
199    ) {
200        ViewObject::paint(&mut self.view, bounds, element, cx)
201    }
202}
203
204trait ViewObject: Send + Sync {
205    fn entity_type(&self) -> TypeId;
206    fn entity_id(&self) -> EntityId;
207    fn model(&self) -> AnyModel;
208    fn initialize(&self, cx: &mut WindowContext) -> AnyBox;
209    fn layout(&self, element: &mut AnyBox, cx: &mut WindowContext) -> LayoutId;
210    fn paint(&self, bounds: Bounds<Pixels>, element: &mut AnyBox, cx: &mut WindowContext);
211    fn debug(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result;
212}
213
214impl<V> ViewObject for View<V>
215where
216    V: Render,
217{
218    fn entity_type(&self) -> TypeId {
219        TypeId::of::<V>()
220    }
221
222    fn entity_id(&self) -> EntityId {
223        Entity::entity_id(self)
224    }
225
226    fn model(&self) -> AnyModel {
227        self.model.clone().into_any()
228    }
229
230    fn initialize(&self, cx: &mut WindowContext) -> AnyBox {
231        cx.with_element_id(ViewObject::entity_id(self), |_global_id, cx| {
232            self.update(cx, |state, cx| {
233                let mut any_element = Box::new(AnyElement::new(state.render(cx)));
234                any_element.initialize(state, cx);
235                any_element
236            })
237        })
238    }
239
240    fn layout(&self, element: &mut AnyBox, cx: &mut WindowContext) -> LayoutId {
241        cx.with_element_id(ViewObject::entity_id(self), |_global_id, cx| {
242            self.update(cx, |state, cx| {
243                let element = element.downcast_mut::<AnyElement<V>>().unwrap();
244                element.layout(state, cx)
245            })
246        })
247    }
248
249    fn paint(&self, _: Bounds<Pixels>, element: &mut AnyBox, cx: &mut WindowContext) {
250        cx.with_element_id(ViewObject::entity_id(self), |_global_id, cx| {
251            self.update(cx, |state, cx| {
252                let element = element.downcast_mut::<AnyElement<V>>().unwrap();
253                element.paint(state, cx);
254            });
255        });
256    }
257
258    fn debug(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
259        f.debug_struct(&format!("AnyView<{}>", std::any::type_name::<V>()))
260            .field("entity_id", &ViewObject::entity_id(self).as_u64())
261            .finish()
262    }
263}
264
265#[derive(Clone, Debug)]
266pub struct AnyView {
267    model: AnyModel,
268    initialize: fn(&AnyView, &mut WindowContext) -> AnyBox,
269    layout: fn(&AnyView, &mut AnyBox, &mut WindowContext) -> LayoutId,
270    paint: fn(&AnyView, &mut AnyBox, &mut WindowContext),
271}
272
273impl AnyView {
274    pub fn downgrade(&self) -> AnyWeakView {
275        AnyWeakView {
276            model: self.model.downgrade(),
277            initialize: self.initialize,
278            layout: self.layout,
279            paint: self.paint,
280        }
281    }
282
283    pub fn downcast<T: 'static>(self) -> Result<View<T>, Self> {
284        match self.model.downcast() {
285            Ok(model) => Ok(View { model }),
286            Err(model) => Err(Self {
287                model,
288                initialize: self.initialize,
289                layout: self.layout,
290                paint: self.paint,
291            }),
292        }
293    }
294
295    pub(crate) fn entity_type(&self) -> TypeId {
296        self.model.entity_type
297    }
298
299    pub(crate) fn draw(&self, available_space: Size<AvailableSpace>, cx: &mut WindowContext) {
300        let mut rendered_element = (self.initialize)(self, cx);
301        let layout_id = (self.layout)(self, &mut rendered_element, cx);
302        cx.window
303            .layout_engine
304            .compute_layout(layout_id, available_space);
305        (self.paint)(self, &mut rendered_element, cx);
306    }
307}
308
309impl<V: 'static> Component<V> for AnyView {
310    fn render(self) -> AnyElement<V> {
311        AnyElement::new(self)
312    }
313}
314
315impl<V: Render> From<View<V>> for AnyView {
316    fn from(value: View<V>) -> Self {
317        AnyView {
318            model: value.model.into_any(),
319            initialize: |view, cx| {
320                cx.with_element_id(view.model.entity_id, |_, cx| {
321                    let view = view.clone().downcast::<V>().unwrap();
322                    let element = view.update(cx, |view, cx| {
323                        let mut element = AnyElement::new(view.render(cx));
324                        element.initialize(view, cx);
325                        element
326                    });
327                    Box::new(element)
328                })
329            },
330            layout: |view, element, cx| {
331                cx.with_element_id(view.model.entity_id, |_, cx| {
332                    let view = view.clone().downcast::<V>().unwrap();
333                    let element = element.downcast_mut::<AnyElement<V>>().unwrap();
334                    view.update(cx, |view, cx| element.layout(view, cx))
335                })
336            },
337            paint: |view, element, cx| {
338                cx.with_element_id(view.model.entity_id, |_, cx| {
339                    let view = view.clone().downcast::<V>().unwrap();
340                    let element = element.downcast_mut::<AnyElement<V>>().unwrap();
341                    view.update(cx, |view, cx| element.paint(view, cx))
342                })
343            },
344        }
345    }
346}
347
348impl<ParentViewState: 'static> Element<ParentViewState> for AnyView {
349    type ElementState = Box<dyn Any>;
350
351    fn id(&self) -> Option<ElementId> {
352        Some(self.model.entity_id.into())
353    }
354
355    fn initialize(
356        &mut self,
357        _view_state: &mut ParentViewState,
358        _element_state: Option<Self::ElementState>,
359        cx: &mut ViewContext<ParentViewState>,
360    ) -> Self::ElementState {
361        (self.initialize)(self, cx)
362    }
363
364    fn layout(
365        &mut self,
366        _view_state: &mut ParentViewState,
367        rendered_element: &mut Self::ElementState,
368        cx: &mut ViewContext<ParentViewState>,
369    ) -> LayoutId {
370        (self.layout)(self, rendered_element, cx)
371    }
372
373    fn paint(
374        &mut self,
375        _bounds: Bounds<Pixels>,
376        _view_state: &mut ParentViewState,
377        rendered_element: &mut Self::ElementState,
378        cx: &mut ViewContext<ParentViewState>,
379    ) {
380        (self.paint)(self, rendered_element, cx)
381    }
382}
383
384pub struct AnyWeakView {
385    model: AnyWeakModel,
386    initialize: fn(&AnyView, &mut WindowContext) -> AnyBox,
387    layout: fn(&AnyView, &mut AnyBox, &mut WindowContext) -> LayoutId,
388    paint: fn(&AnyView, &mut AnyBox, &mut WindowContext),
389}
390
391impl AnyWeakView {
392    pub fn upgrade(&self) -> Option<AnyView> {
393        let model = self.model.upgrade()?;
394        Some(AnyView {
395            model,
396            initialize: self.initialize,
397            layout: self.layout,
398            paint: self.paint,
399        })
400    }
401}
402
403impl<T, E> Render for T
404where
405    T: 'static + FnMut(&mut WindowContext) -> E,
406    E: 'static + Send + Element<T>,
407{
408    type Element = E;
409
410    fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
411        (self)(cx)
412    }
413}