view.rs

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