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