view.rs

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