view.rs

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