view.rs

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