view.rs

  1use crate::{
  2    seal::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::{type_name, 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 focus_handle(&self, cx: &AppContext) -> FocusHandle
 64    where
 65        V: FocusableView,
 66    {
 67        self.read(cx).focus_handle(cx)
 68    }
 69}
 70
 71impl<V: Render> Element for View<V> {
 72    type State = Option<AnyElement>;
 73
 74    fn request_layout(
 75        &mut self,
 76        _state: Option<Self::State>,
 77        cx: &mut WindowContext,
 78    ) -> (LayoutId, Self::State) {
 79        let mut element = self.update(cx, |view, cx| view.render(cx).into_any_element());
 80        let layout_id = element.request_layout(cx);
 81        (layout_id, Some(element))
 82    }
 83
 84    fn paint(&mut self, _: Bounds<Pixels>, element: &mut Self::State, cx: &mut WindowContext) {
 85        element.take().unwrap().paint(cx);
 86    }
 87}
 88
 89impl<V> Clone for View<V> {
 90    fn clone(&self) -> Self {
 91        Self {
 92            model: self.model.clone(),
 93        }
 94    }
 95}
 96
 97impl<T> std::fmt::Debug for View<T> {
 98    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 99        f.debug_struct(&format!("View<{}>", type_name::<T>()))
100            .field("entity_id", &self.model.entity_id)
101            .finish_non_exhaustive()
102    }
103}
104
105impl<V> Hash for View<V> {
106    fn hash<H: Hasher>(&self, state: &mut H) {
107        self.model.hash(state);
108    }
109}
110
111impl<V> PartialEq for View<V> {
112    fn eq(&self, other: &Self) -> bool {
113        self.model == other.model
114    }
115}
116
117impl<V> Eq for View<V> {}
118
119pub struct WeakView<V> {
120    pub(crate) model: WeakModel<V>,
121}
122
123impl<V: 'static> WeakView<V> {
124    pub fn entity_id(&self) -> EntityId {
125        self.model.entity_id
126    }
127
128    pub fn upgrade(&self) -> Option<View<V>> {
129        Entity::upgrade_from(self)
130    }
131
132    pub fn update<C, R>(
133        &self,
134        cx: &mut C,
135        f: impl FnOnce(&mut V, &mut ViewContext<'_, V>) -> R,
136    ) -> Result<R>
137    where
138        C: VisualContext,
139        Result<C::Result<R>>: Flatten<R>,
140    {
141        let view = self.upgrade().context("error upgrading view")?;
142        Ok(view.update(cx, f)).flatten()
143    }
144
145    #[cfg(any(test, feature = "test-support"))]
146    pub fn assert_dropped(&self) {
147        self.model.assert_dropped()
148    }
149}
150
151impl<V> Clone for WeakView<V> {
152    fn clone(&self) -> Self {
153        Self {
154            model: self.model.clone(),
155        }
156    }
157}
158
159impl<V> Hash for WeakView<V> {
160    fn hash<H: Hasher>(&self, state: &mut H) {
161        self.model.hash(state);
162    }
163}
164
165impl<V> PartialEq for WeakView<V> {
166    fn eq(&self, other: &Self) -> bool {
167        self.model == other.model
168    }
169}
170
171impl<V> Eq for WeakView<V> {}
172
173#[derive(Clone, Debug)]
174pub struct AnyView {
175    model: AnyModel,
176    layout: fn(&AnyView, &mut WindowContext) -> (LayoutId, AnyElement),
177    paint: fn(&AnyView, &mut AnyElement, &mut WindowContext),
178}
179
180impl AnyView {
181    pub fn downgrade(&self) -> AnyWeakView {
182        AnyWeakView {
183            model: self.model.downgrade(),
184            layout: self.layout,
185            paint: self.paint,
186        }
187    }
188
189    pub fn downcast<T: 'static>(self) -> Result<View<T>, Self> {
190        match self.model.downcast() {
191            Ok(model) => Ok(View { model }),
192            Err(model) => Err(Self {
193                model,
194                layout: self.layout,
195                paint: self.paint,
196            }),
197        }
198    }
199
200    pub fn entity_type(&self) -> TypeId {
201        self.model.entity_type
202    }
203
204    pub fn entity_id(&self) -> EntityId {
205        self.model.entity_id()
206    }
207
208    pub(crate) fn draw(
209        &self,
210        origin: Point<Pixels>,
211        available_space: Size<AvailableSpace>,
212        cx: &mut WindowContext,
213    ) {
214        cx.with_absolute_element_offset(origin, |cx| {
215            let (layout_id, mut rendered_element) = (self.layout)(self, cx);
216            cx.compute_layout(layout_id, available_space);
217            (self.paint)(self, &mut rendered_element, cx);
218        })
219    }
220}
221
222impl<V: Render> From<View<V>> for AnyView {
223    fn from(value: View<V>) -> Self {
224        AnyView {
225            model: value.model.into_any(),
226            layout: any_view::layout::<V>,
227            paint: any_view::paint,
228        }
229    }
230}
231
232impl Element for AnyView {
233    type State = Option<AnyElement>;
234
235    fn request_layout(
236        &mut self,
237        _state: Option<Self::State>,
238        cx: &mut WindowContext,
239    ) -> (LayoutId, Self::State) {
240        let (layout_id, state) = (self.layout)(self, cx);
241        (layout_id, Some(state))
242    }
243
244    fn paint(&mut self, _: Bounds<Pixels>, state: &mut Self::State, cx: &mut WindowContext) {
245        debug_assert!(
246            state.is_some(),
247            "state is None. Did you include an AnyView twice in the tree?"
248        );
249        (self.paint)(self, state.as_mut().unwrap(), cx)
250    }
251}
252
253impl<V: 'static + Render> IntoElement for View<V> {
254    type Element = View<V>;
255
256    fn element_id(&self) -> Option<ElementId> {
257        Some(ElementId::from_entity_id(self.model.entity_id))
258    }
259
260    fn into_element(self) -> Self::Element {
261        self
262    }
263}
264
265impl IntoElement for AnyView {
266    type Element = Self;
267
268    fn element_id(&self) -> Option<ElementId> {
269        Some(ElementId::from_entity_id(self.model.entity_id))
270    }
271
272    fn into_element(self) -> Self::Element {
273        self
274    }
275}
276
277pub struct AnyWeakView {
278    model: AnyWeakModel,
279    layout: fn(&AnyView, &mut WindowContext) -> (LayoutId, AnyElement),
280    paint: fn(&AnyView, &mut AnyElement, &mut WindowContext),
281}
282
283impl AnyWeakView {
284    pub fn upgrade(&self) -> Option<AnyView> {
285        let model = self.model.upgrade()?;
286        Some(AnyView {
287            model,
288            layout: self.layout,
289            paint: self.paint,
290        })
291    }
292}
293
294impl<V: 'static + Render> From<WeakView<V>> for AnyWeakView {
295    fn from(view: WeakView<V>) -> Self {
296        Self {
297            model: view.model.into(),
298            layout: any_view::layout::<V>,
299            paint: any_view::paint,
300        }
301    }
302}
303
304impl PartialEq for AnyWeakView {
305    fn eq(&self, other: &Self) -> bool {
306        self.model == other.model
307    }
308}
309
310impl std::fmt::Debug for AnyWeakView {
311    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
312        f.debug_struct("AnyWeakView")
313            .field("entity_id", &self.model.entity_id)
314            .finish_non_exhaustive()
315    }
316}
317
318mod any_view {
319    use crate::{AnyElement, AnyView, IntoElement, LayoutId, Render, WindowContext};
320
321    pub(crate) fn layout<V: 'static + Render>(
322        view: &AnyView,
323        cx: &mut WindowContext,
324    ) -> (LayoutId, AnyElement) {
325        let view = view.clone().downcast::<V>().unwrap();
326        let mut element = view.update(cx, |view, cx| view.render(cx).into_any_element());
327        let layout_id = element.request_layout(cx);
328        (layout_id, element)
329    }
330
331    pub(crate) fn paint(_view: &AnyView, element: &mut AnyElement, cx: &mut WindowContext) {
332        element.paint(cx);
333    }
334}