view.rs

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