view.rs

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