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