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