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
 68impl<V> Clone for View<V> {
 69    fn clone(&self) -> Self {
 70        Self {
 71            model: self.model.clone(),
 72        }
 73    }
 74}
 75
 76impl<V> Hash for View<V> {
 77    fn hash<H: Hasher>(&self, state: &mut H) {
 78        self.model.hash(state);
 79    }
 80}
 81
 82impl<V> PartialEq for View<V> {
 83    fn eq(&self, other: &Self) -> bool {
 84        self.model == other.model
 85    }
 86}
 87
 88impl<V> Eq for View<V> {}
 89
 90impl<V: Render, ParentViewState: 'static> Component<ParentViewState> for View<V> {
 91    fn render(self) -> AnyElement<ParentViewState> {
 92        AnyElement::new(AnyView::from(self))
 93    }
 94}
 95
 96pub struct WeakView<V> {
 97    pub(crate) model: WeakModel<V>,
 98}
 99
100impl<V: 'static> WeakView<V> {
101    pub fn upgrade(&self) -> Option<View<V>> {
102        Entity::upgrade_from(self)
103    }
104
105    pub fn update<C, R>(
106        &self,
107        cx: &mut C,
108        f: impl FnOnce(&mut V, &mut ViewContext<'_, V>) -> R,
109    ) -> Result<R>
110    where
111        C: VisualContext,
112        Result<C::Result<R>>: Flatten<R>,
113    {
114        let view = self.upgrade().context("error upgrading view")?;
115        Ok(view.update(cx, f)).flatten()
116    }
117}
118
119impl<V> Clone for WeakView<V> {
120    fn clone(&self) -> Self {
121        Self {
122            model: self.model.clone(),
123        }
124    }
125}
126
127impl<V> Hash for WeakView<V> {
128    fn hash<H: Hasher>(&self, state: &mut H) {
129        self.model.hash(state);
130    }
131}
132
133impl<V> PartialEq for WeakView<V> {
134    fn eq(&self, other: &Self) -> bool {
135        self.model == other.model
136    }
137}
138
139impl<V> Eq for WeakView<V> {}
140
141#[derive(Clone, Debug)]
142pub struct AnyView {
143    model: AnyModel,
144    initialize: fn(&AnyView, &mut WindowContext) -> AnyBox,
145    layout: fn(&AnyView, &mut AnyBox, &mut WindowContext) -> LayoutId,
146    paint: fn(&AnyView, &mut AnyBox, &mut WindowContext),
147}
148
149impl AnyView {
150    pub fn downgrade(&self) -> AnyWeakView {
151        AnyWeakView {
152            model: self.model.downgrade(),
153            initialize: self.initialize,
154            layout: self.layout,
155            paint: self.paint,
156        }
157    }
158
159    pub fn downcast<T: 'static>(self) -> Result<View<T>, Self> {
160        match self.model.downcast() {
161            Ok(model) => Ok(View { model }),
162            Err(model) => Err(Self {
163                model,
164                initialize: self.initialize,
165                layout: self.layout,
166                paint: self.paint,
167            }),
168        }
169    }
170
171    pub fn entity_type(&self) -> TypeId {
172        self.model.entity_type
173    }
174
175    pub(crate) fn draw(&self, available_space: Size<AvailableSpace>, cx: &mut WindowContext) {
176        let mut rendered_element = (self.initialize)(self, cx);
177        let layout_id = (self.layout)(self, &mut rendered_element, cx);
178        cx.window
179            .layout_engine
180            .compute_layout(layout_id, available_space);
181        (self.paint)(self, &mut rendered_element, cx);
182    }
183}
184
185impl<V: 'static> Component<V> for AnyView {
186    fn render(self) -> AnyElement<V> {
187        AnyElement::new(self)
188    }
189}
190
191impl<V: Render> From<View<V>> for AnyView {
192    fn from(value: View<V>) -> Self {
193        AnyView {
194            model: value.model.into_any(),
195            initialize: |view, cx| {
196                cx.with_element_id(view.model.entity_id, |_, cx| {
197                    let view = view.clone().downcast::<V>().unwrap();
198                    let element = view.update(cx, |view, cx| {
199                        let mut element = AnyElement::new(view.render(cx));
200                        element.initialize(view, cx);
201                        element
202                    });
203                    Box::new(element)
204                })
205            },
206            layout: |view, element, cx| {
207                cx.with_element_id(view.model.entity_id, |_, cx| {
208                    let view = view.clone().downcast::<V>().unwrap();
209                    let element = element.downcast_mut::<AnyElement<V>>().unwrap();
210                    view.update(cx, |view, cx| element.layout(view, cx))
211                })
212            },
213            paint: |view, element, cx| {
214                cx.with_element_id(view.model.entity_id, |_, cx| {
215                    let view = view.clone().downcast::<V>().unwrap();
216                    let element = element.downcast_mut::<AnyElement<V>>().unwrap();
217                    view.update(cx, |view, cx| element.paint(view, cx))
218                })
219            },
220        }
221    }
222}
223
224impl<ParentViewState: 'static> Element<ParentViewState> for AnyView {
225    type ElementState = Box<dyn Any>;
226
227    fn id(&self) -> Option<ElementId> {
228        Some(self.model.entity_id.into())
229    }
230
231    fn initialize(
232        &mut self,
233        _view_state: &mut ParentViewState,
234        _element_state: Option<Self::ElementState>,
235        cx: &mut ViewContext<ParentViewState>,
236    ) -> Self::ElementState {
237        (self.initialize)(self, cx)
238    }
239
240    fn layout(
241        &mut self,
242        _view_state: &mut ParentViewState,
243        rendered_element: &mut Self::ElementState,
244        cx: &mut ViewContext<ParentViewState>,
245    ) -> LayoutId {
246        (self.layout)(self, rendered_element, cx)
247    }
248
249    fn paint(
250        &mut self,
251        _bounds: Bounds<Pixels>,
252        _view_state: &mut ParentViewState,
253        rendered_element: &mut Self::ElementState,
254        cx: &mut ViewContext<ParentViewState>,
255    ) {
256        (self.paint)(self, rendered_element, cx)
257    }
258}
259
260pub struct AnyWeakView {
261    model: AnyWeakModel,
262    initialize: fn(&AnyView, &mut WindowContext) -> AnyBox,
263    layout: fn(&AnyView, &mut AnyBox, &mut WindowContext) -> LayoutId,
264    paint: fn(&AnyView, &mut AnyBox, &mut WindowContext),
265}
266
267impl AnyWeakView {
268    pub fn upgrade(&self) -> Option<AnyView> {
269        let model = self.model.upgrade()?;
270        Some(AnyView {
271            model,
272            initialize: self.initialize,
273            layout: self.layout,
274            paint: self.paint,
275        })
276    }
277}
278
279impl<T, E> Render for T
280where
281    T: 'static + FnMut(&mut WindowContext) -> E,
282    E: 'static + Send + Element<T>,
283{
284    type Element = E;
285
286    fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
287        (self)(cx)
288    }
289}