view.rs

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