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, Point, 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    layout: fn(&AnyView, &mut WindowContext) -> (LayoutId, Box<dyn Any>),
159    paint: fn(&AnyView, &mut AnyBox, &mut WindowContext),
160}
161
162impl AnyView {
163    pub fn downgrade(&self) -> AnyWeakView {
164        AnyWeakView {
165            model: self.model.downgrade(),
166            layout: self.layout,
167            paint: self.paint,
168        }
169    }
170
171    pub fn downcast<T: 'static>(self) -> Result<View<T>, Self> {
172        match self.model.downcast() {
173            Ok(model) => Ok(View { model }),
174            Err(model) => Err(Self {
175                model,
176                layout: self.layout,
177                paint: self.paint,
178            }),
179        }
180    }
181
182    pub fn entity_type(&self) -> TypeId {
183        self.model.entity_type
184    }
185
186    pub(crate) fn draw(
187        &self,
188        origin: Point<Pixels>,
189        available_space: Size<AvailableSpace>,
190        cx: &mut WindowContext,
191    ) {
192        cx.with_absolute_element_offset(origin, |cx| {
193            let (layout_id, mut rendered_element) = (self.layout)(self, cx);
194            cx.window
195                .layout_engine
196                .compute_layout(layout_id, available_space);
197            (self.paint)(self, &mut rendered_element, cx);
198        })
199    }
200}
201
202impl<V: 'static> Component<V> for AnyView {
203    fn render(self) -> AnyElement<V> {
204        AnyElement::new(self)
205    }
206}
207
208impl<V: Render> From<View<V>> for AnyView {
209    fn from(value: View<V>) -> Self {
210        AnyView {
211            model: value.model.into_any(),
212            layout: any_view::layout::<V>,
213            paint: any_view::paint::<V>,
214        }
215    }
216}
217
218impl<ParentViewState: 'static> Element<ParentViewState> for AnyView {
219    type ElementState = Box<dyn Any>;
220
221    fn element_id(&self) -> Option<ElementId> {
222        Some(self.model.entity_id.into())
223    }
224
225    fn layout(
226        &mut self,
227        _view_state: &mut ParentViewState,
228        _element_state: Option<Self::ElementState>,
229        cx: &mut ViewContext<ParentViewState>,
230    ) -> (LayoutId, Self::ElementState) {
231        (self.layout)(self, cx)
232    }
233
234    fn paint(
235        &mut self,
236        _bounds: Bounds<Pixels>,
237        _view_state: &mut ParentViewState,
238        rendered_element: &mut Self::ElementState,
239        cx: &mut ViewContext<ParentViewState>,
240    ) {
241        (self.paint)(self, rendered_element, cx)
242    }
243}
244
245pub struct AnyWeakView {
246    model: AnyWeakModel,
247    layout: fn(&AnyView, &mut WindowContext) -> (LayoutId, Box<dyn Any>),
248    paint: fn(&AnyView, &mut AnyBox, &mut WindowContext),
249}
250
251impl AnyWeakView {
252    pub fn upgrade(&self) -> Option<AnyView> {
253        let model = self.model.upgrade()?;
254        Some(AnyView {
255            model,
256            layout: self.layout,
257            paint: self.paint,
258        })
259    }
260}
261
262impl<V: Render> From<WeakView<V>> for AnyWeakView {
263    fn from(view: WeakView<V>) -> Self {
264        Self {
265            model: view.model.into(),
266            layout: any_view::layout::<V>,
267            paint: any_view::paint::<V>,
268        }
269    }
270}
271
272impl<T, E> Render for T
273where
274    T: 'static + FnMut(&mut WindowContext) -> E,
275    E: 'static + Send + Element<T>,
276{
277    type Element = E;
278
279    fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
280        (self)(cx)
281    }
282}
283
284pub struct RenderViewWith<C, V> {
285    view: View<V>,
286    component: Option<C>,
287}
288
289impl<C, ParentViewState, ViewState> Component<ParentViewState> for RenderViewWith<C, ViewState>
290where
291    C: 'static + Component<ViewState>,
292    ParentViewState: 'static,
293    ViewState: 'static,
294{
295    fn render(self) -> AnyElement<ParentViewState> {
296        AnyElement::new(self)
297    }
298}
299
300impl<C, ParentViewState, ViewState> Element<ParentViewState> for RenderViewWith<C, ViewState>
301where
302    C: 'static + Component<ViewState>,
303    ParentViewState: 'static,
304    ViewState: 'static,
305{
306    type ElementState = AnyElement<ViewState>;
307
308    fn element_id(&self) -> Option<ElementId> {
309        Some(self.view.entity_id().into())
310    }
311
312    fn layout(
313        &mut self,
314        _: &mut ParentViewState,
315        _: Option<Self::ElementState>,
316        cx: &mut ViewContext<ParentViewState>,
317    ) -> (LayoutId, Self::ElementState) {
318        self.view.update(cx, |view, cx| {
319            let mut element = self.component.take().unwrap().render();
320            let layout_id = element.layout(view, cx);
321            (layout_id, element)
322        })
323    }
324
325    fn paint(
326        &mut self,
327        _: Bounds<Pixels>,
328        _: &mut ParentViewState,
329        element: &mut Self::ElementState,
330        cx: &mut ViewContext<ParentViewState>,
331    ) {
332        self.view.update(cx, |view, cx| element.paint(view, cx))
333    }
334}
335
336mod any_view {
337    use crate::{AnyElement, AnyView, BorrowWindow, LayoutId, Render, WindowContext};
338    use std::any::Any;
339
340    pub(crate) fn layout<V: Render>(
341        view: &AnyView,
342        cx: &mut WindowContext,
343    ) -> (LayoutId, Box<dyn Any>) {
344        cx.with_element_id(Some(view.model.entity_id), |cx| {
345            let view = view.clone().downcast::<V>().unwrap();
346            view.update(cx, |view, cx| {
347                let mut element = AnyElement::new(view.render(cx));
348                let layout_id = element.layout(view, cx);
349                (layout_id, Box::new(element) as Box<dyn Any>)
350            })
351        })
352    }
353
354    pub(crate) fn paint<V: Render>(
355        view: &AnyView,
356        element: &mut Box<dyn Any>,
357        cx: &mut WindowContext,
358    ) {
359        cx.with_element_id(Some(view.model.entity_id), |cx| {
360            let view = view.clone().downcast::<V>().unwrap();
361            let element = element.downcast_mut::<AnyElement<V>>().unwrap();
362            view.update(cx, |view, cx| element.paint(view, cx))
363        })
364    }
365}