view.rs

  1use crate::{
  2    private::Sealed, AnyBox, AnyElement, AnyModel, AnyWeakModel, AppContext, AvailableSpace,
  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::{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 entity_id(&self) -> EntityId {
102        self.model.entity_id
103    }
104
105    pub fn upgrade(&self) -> Option<View<V>> {
106        Entity::upgrade_from(self)
107    }
108
109    pub fn update<C, R>(
110        &self,
111        cx: &mut C,
112        f: impl FnOnce(&mut V, &mut ViewContext<'_, V>) -> R,
113    ) -> Result<R>
114    where
115        C: VisualContext,
116        Result<C::Result<R>>: Flatten<R>,
117    {
118        let view = self.upgrade().context("error upgrading view")?;
119        Ok(view.update(cx, f)).flatten()
120    }
121}
122
123impl<V> Clone for WeakView<V> {
124    fn clone(&self) -> Self {
125        Self {
126            model: self.model.clone(),
127        }
128    }
129}
130
131impl<V> Hash for WeakView<V> {
132    fn hash<H: Hasher>(&self, state: &mut H) {
133        self.model.hash(state);
134    }
135}
136
137impl<V> PartialEq for WeakView<V> {
138    fn eq(&self, other: &Self) -> bool {
139        self.model == other.model
140    }
141}
142
143impl<V> Eq for WeakView<V> {}
144
145#[derive(Clone, Debug)]
146pub struct AnyView {
147    model: AnyModel,
148    initialize: fn(&AnyView, &mut WindowContext) -> AnyBox,
149    layout: fn(&AnyView, &mut AnyBox, &mut WindowContext) -> LayoutId,
150    paint: fn(&AnyView, &mut AnyBox, &mut WindowContext),
151}
152
153impl AnyView {
154    pub fn downgrade(&self) -> AnyWeakView {
155        AnyWeakView {
156            model: self.model.downgrade(),
157            initialize: self.initialize,
158            layout: self.layout,
159            paint: self.paint,
160        }
161    }
162
163    pub fn downcast<T: 'static>(self) -> Result<View<T>, Self> {
164        match self.model.downcast() {
165            Ok(model) => Ok(View { model }),
166            Err(model) => Err(Self {
167                model,
168                initialize: self.initialize,
169                layout: self.layout,
170                paint: self.paint,
171            }),
172        }
173    }
174
175    pub fn entity_type(&self) -> TypeId {
176        self.model.entity_type
177    }
178
179    pub(crate) fn draw(&self, available_space: Size<AvailableSpace>, cx: &mut WindowContext) {
180        let mut rendered_element = (self.initialize)(self, cx);
181        let layout_id = (self.layout)(self, &mut rendered_element, cx);
182        cx.window
183            .layout_engine
184            .compute_layout(layout_id, available_space);
185        (self.paint)(self, &mut rendered_element, cx);
186    }
187
188    pub(crate) fn draw_dispatch_stack(&self, cx: &mut WindowContext) {
189        (self.initialize)(self, cx);
190    }
191}
192
193impl<V: 'static> Component<V> for AnyView {
194    fn render(self) -> AnyElement<V> {
195        AnyElement::new(self)
196    }
197}
198
199impl<V: Render> From<View<V>> for AnyView {
200    fn from(value: View<V>) -> Self {
201        AnyView {
202            model: value.model.into_any(),
203            initialize: any_view::initialize::<V>,
204            layout: any_view::layout::<V>,
205            paint: any_view::paint::<V>,
206        }
207    }
208}
209
210impl<ParentViewState: 'static> Element<ParentViewState> for AnyView {
211    type ElementState = Box<dyn Any>;
212
213    fn id(&self) -> Option<ElementId> {
214        Some(self.model.entity_id.into())
215    }
216
217    fn initialize(
218        &mut self,
219        _view_state: &mut ParentViewState,
220        _element_state: Option<Self::ElementState>,
221        cx: &mut ViewContext<ParentViewState>,
222    ) -> Self::ElementState {
223        (self.initialize)(self, cx)
224    }
225
226    fn layout(
227        &mut self,
228        _view_state: &mut ParentViewState,
229        rendered_element: &mut Self::ElementState,
230        cx: &mut ViewContext<ParentViewState>,
231    ) -> LayoutId {
232        (self.layout)(self, rendered_element, cx)
233    }
234
235    fn paint(
236        &mut self,
237        _bounds: Bounds<Pixels>,
238        _view_state: &mut ParentViewState,
239        rendered_element: &mut Self::ElementState,
240        cx: &mut ViewContext<ParentViewState>,
241    ) {
242        (self.paint)(self, rendered_element, cx)
243    }
244}
245
246pub struct AnyWeakView {
247    model: AnyWeakModel,
248    initialize: fn(&AnyView, &mut WindowContext) -> AnyBox,
249    layout: fn(&AnyView, &mut AnyBox, &mut WindowContext) -> LayoutId,
250    paint: fn(&AnyView, &mut AnyBox, &mut WindowContext),
251}
252
253impl AnyWeakView {
254    pub fn upgrade(&self) -> Option<AnyView> {
255        let model = self.model.upgrade()?;
256        Some(AnyView {
257            model,
258            initialize: self.initialize,
259            layout: self.layout,
260            paint: self.paint,
261        })
262    }
263}
264
265impl<V: Render> From<WeakView<V>> for AnyWeakView {
266    fn from(view: WeakView<V>) -> Self {
267        Self {
268            model: view.model.into(),
269            initialize: any_view::initialize::<V>,
270            layout: any_view::layout::<V>,
271            paint: any_view::paint::<V>,
272        }
273    }
274}
275
276impl<T, E> Render for T
277where
278    T: 'static + FnMut(&mut WindowContext) -> E,
279    E: 'static + Send + Element<T>,
280{
281    type Element = E;
282
283    fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
284        (self)(cx)
285    }
286}
287
288mod any_view {
289    use crate::{AnyElement, AnyView, BorrowWindow, LayoutId, Render, WindowContext};
290    use std::any::Any;
291
292    pub(crate) fn initialize<V: Render>(view: &AnyView, cx: &mut WindowContext) -> Box<dyn Any> {
293        cx.with_element_id(view.model.entity_id, |_, cx| {
294            let view = view.clone().downcast::<V>().unwrap();
295            let element = view.update(cx, |view, cx| {
296                let mut element = AnyElement::new(view.render(cx));
297                element.initialize(view, cx);
298                element
299            });
300            Box::new(element)
301        })
302    }
303
304    pub(crate) fn layout<V: Render>(
305        view: &AnyView,
306        element: &mut Box<dyn Any>,
307        cx: &mut WindowContext,
308    ) -> LayoutId {
309        cx.with_element_id(view.model.entity_id, |_, cx| {
310            let view = view.clone().downcast::<V>().unwrap();
311            let element = element.downcast_mut::<AnyElement<V>>().unwrap();
312            view.update(cx, |view, cx| element.layout(view, cx))
313        })
314    }
315
316    pub(crate) fn paint<V: Render>(
317        view: &AnyView,
318        element: &mut Box<dyn Any>,
319        cx: &mut WindowContext,
320    ) {
321        cx.with_element_id(view.model.entity_id, |_, cx| {
322            let view = view.clone().downcast::<V>().unwrap();
323            let element = element.downcast_mut::<AnyElement<V>>().unwrap();
324            view.update(cx, |view, cx| element.paint(view, cx))
325        })
326    }
327}