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
181struct EraseViewState<V, ParentV> {
182    view: View<V>,
183    parent_view_state_type: PhantomData<ParentV>,
184}
185
186unsafe impl<V, ParentV> Send for EraseViewState<V, ParentV> {}
187
188impl<V: Render, ParentV: 'static> Component<ParentV> for EraseViewState<V, ParentV> {
189    fn render(self) -> AnyElement<ParentV> {
190        AnyElement::new(self)
191    }
192}
193
194impl<V: Render, ParentV: 'static> Element<ParentV> for EraseViewState<V, ParentV> {
195    type ElementState = AnyBox;
196
197    fn id(&self) -> Option<ElementId> {
198        Element::id(&self.view)
199    }
200
201    fn initialize(
202        &mut self,
203        _: &mut ParentV,
204        _: Option<Self::ElementState>,
205        cx: &mut ViewContext<ParentV>,
206    ) -> Self::ElementState {
207        ViewObject::initialize(&mut self.view, cx)
208    }
209
210    fn layout(
211        &mut self,
212        _: &mut ParentV,
213        element: &mut Self::ElementState,
214        cx: &mut ViewContext<ParentV>,
215    ) -> LayoutId {
216        ViewObject::layout(&mut self.view, element, cx)
217    }
218
219    fn paint(
220        &mut self,
221        bounds: Bounds<Pixels>,
222        _: &mut ParentV,
223        element: &mut Self::ElementState,
224        cx: &mut ViewContext<ParentV>,
225    ) {
226        ViewObject::paint(&mut self.view, bounds, element, cx)
227    }
228}
229
230trait ViewObject: Send + Sync {
231    fn entity_type(&self) -> TypeId;
232    fn entity_id(&self) -> EntityId;
233    fn model(&self) -> AnyModel;
234    fn initialize(&self, cx: &mut WindowContext) -> AnyBox;
235    fn layout(&self, element: &mut AnyBox, cx: &mut WindowContext) -> LayoutId;
236    fn paint(&self, bounds: Bounds<Pixels>, element: &mut AnyBox, cx: &mut WindowContext);
237    fn debug(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result;
238}
239
240impl<V> ViewObject for View<V>
241where
242    V: Render,
243{
244    fn entity_type(&self) -> TypeId {
245        TypeId::of::<V>()
246    }
247
248    fn entity_id(&self) -> EntityId {
249        Entity::entity_id(self)
250    }
251
252    fn model(&self) -> AnyModel {
253        self.model.clone().into_any()
254    }
255
256    fn initialize(&self, cx: &mut WindowContext) -> AnyBox {
257        cx.with_element_id(ViewObject::entity_id(self), |_global_id, cx| {
258            self.update(cx, |state, cx| {
259                let mut any_element = Box::new(AnyElement::new(state.render(cx)));
260                any_element.initialize(state, cx);
261                any_element
262            })
263        })
264    }
265
266    fn layout(&self, element: &mut AnyBox, cx: &mut WindowContext) -> LayoutId {
267        cx.with_element_id(ViewObject::entity_id(self), |_global_id, cx| {
268            self.update(cx, |state, cx| {
269                let element = element.downcast_mut::<AnyElement<V>>().unwrap();
270                element.layout(state, cx)
271            })
272        })
273    }
274
275    fn paint(&self, _: Bounds<Pixels>, element: &mut AnyBox, cx: &mut WindowContext) {
276        cx.with_element_id(ViewObject::entity_id(self), |_global_id, cx| {
277            self.update(cx, |state, cx| {
278                let element = element.downcast_mut::<AnyElement<V>>().unwrap();
279                element.paint(state, cx);
280            });
281        });
282    }
283
284    fn debug(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
285        f.debug_struct(&format!("AnyView<{}>", std::any::type_name::<V>()))
286            .field("entity_id", &ViewObject::entity_id(self).as_u64())
287            .finish()
288    }
289}
290
291#[derive(Clone)]
292pub struct AnyView(Arc<dyn ViewObject>);
293
294impl AnyView {
295    pub fn downcast<V: 'static>(self) -> Result<View<V>, AnyView> {
296        self.0
297            .model()
298            .downcast()
299            .map(|model| View { model })
300            .map_err(|_| self)
301    }
302
303    pub(crate) fn entity_type(&self) -> TypeId {
304        self.0.entity_type()
305    }
306
307    pub(crate) fn draw(&self, available_space: Size<AvailableSpace>, cx: &mut WindowContext) {
308        let mut rendered_element = self.0.initialize(cx);
309        let layout_id = self.0.layout(&mut rendered_element, cx);
310        cx.window
311            .layout_engine
312            .compute_layout(layout_id, available_space);
313        let bounds = cx.window.layout_engine.layout_bounds(layout_id);
314        self.0.paint(bounds, &mut rendered_element, cx);
315    }
316}
317
318impl<ParentV: 'static> Component<ParentV> for AnyView {
319    fn render(self) -> AnyElement<ParentV> {
320        AnyElement::new(EraseAnyViewState {
321            view: self,
322            parent_view_state_type: PhantomData,
323        })
324    }
325}
326
327impl std::fmt::Debug for AnyView {
328    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
329        self.0.debug(f)
330    }
331}
332
333struct EraseAnyViewState<ParentViewState> {
334    view: AnyView,
335    parent_view_state_type: PhantomData<ParentViewState>,
336}
337
338unsafe impl<ParentV> Send for EraseAnyViewState<ParentV> {}
339
340impl<ParentV: 'static> Component<ParentV> for EraseAnyViewState<ParentV> {
341    fn render(self) -> AnyElement<ParentV> {
342        AnyElement::new(self)
343    }
344}
345
346impl<T, E> Render for T
347where
348    T: 'static + FnMut(&mut WindowContext) -> E,
349    E: 'static + Send + Element<T>,
350{
351    type Element = E;
352
353    fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
354        (self)(cx)
355    }
356}
357
358impl<ParentV: 'static> Element<ParentV> for EraseAnyViewState<ParentV> {
359    type ElementState = AnyBox;
360
361    fn id(&self) -> Option<ElementId> {
362        Some(self.view.0.entity_id().into())
363    }
364
365    fn initialize(
366        &mut self,
367        _: &mut ParentV,
368        _: Option<Self::ElementState>,
369        cx: &mut ViewContext<ParentV>,
370    ) -> Self::ElementState {
371        self.view.0.initialize(cx)
372    }
373
374    fn layout(
375        &mut self,
376        _: &mut ParentV,
377        element: &mut Self::ElementState,
378        cx: &mut ViewContext<ParentV>,
379    ) -> LayoutId {
380        self.view.0.layout(element, cx)
381    }
382
383    fn paint(
384        &mut self,
385        bounds: Bounds<Pixels>,
386        _: &mut ParentV,
387        element: &mut Self::ElementState,
388        cx: &mut ViewContext<ParentV>,
389    ) {
390        self.view.0.paint(bounds, element, cx)
391    }
392}