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.window
213                .layout_engine
214                .compute_layout(layout_id, available_space);
215            (self.paint)(self, rendered_element, cx);
216        })
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 Element for AnyView {
231    type State = Option<AnyElement>;
232
233    fn layout(
234        &mut self,
235        _state: Option<Self::State>,
236        cx: &mut WindowContext,
237    ) -> (LayoutId, Self::State) {
238        let (layout_id, state) = (self.layout)(self, cx);
239        (layout_id, Some(state))
240    }
241
242    fn paint(self, _: Bounds<Pixels>, state: &mut Self::State, cx: &mut WindowContext) {
243        (self.paint)(&self, state.take().unwrap(), cx)
244    }
245}
246
247impl<V: 'static + Render> IntoElement for View<V> {
248    type Element = View<V>;
249
250    fn element_id(&self) -> Option<ElementId> {
251        Some(ElementId::from_entity_id(self.model.entity_id))
252    }
253
254    fn into_element(self) -> Self::Element {
255        self
256    }
257}
258
259impl IntoElement for AnyView {
260    type Element = Self;
261
262    fn element_id(&self) -> Option<ElementId> {
263        Some(ElementId::from_entity_id(self.model.entity_id))
264    }
265
266    fn into_element(self) -> Self::Element {
267        self
268    }
269}
270
271pub struct AnyWeakView {
272    model: AnyWeakModel,
273    layout: fn(&AnyView, &mut WindowContext) -> (LayoutId, AnyElement),
274    paint: fn(&AnyView, AnyElement, &mut WindowContext),
275}
276
277impl AnyWeakView {
278    pub fn upgrade(&self) -> Option<AnyView> {
279        let model = self.model.upgrade()?;
280        Some(AnyView {
281            model,
282            layout: self.layout,
283            paint: self.paint,
284        })
285    }
286}
287
288impl<V: 'static + Render> From<WeakView<V>> for AnyWeakView {
289    fn from(view: WeakView<V>) -> Self {
290        Self {
291            model: view.model.into(),
292            layout: any_view::layout::<V>,
293            paint: any_view::paint::<V>,
294        }
295    }
296}
297
298impl<T, E> Render for T
299where
300    T: 'static + FnMut(&mut WindowContext) -> E,
301    E: 'static + Send + Element,
302{
303    type Element = E;
304
305    fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
306        (self)(cx)
307    }
308}
309
310mod any_view {
311    use crate::{AnyElement, AnyView, Element, LayoutId, Render, WindowContext};
312
313    pub(crate) fn layout<V: 'static + Render>(
314        view: &AnyView,
315        cx: &mut WindowContext,
316    ) -> (LayoutId, AnyElement) {
317        let view = view.clone().downcast::<V>().unwrap();
318        let mut element = view.update(cx, |view, cx| view.render(cx).into_any());
319        let layout_id = element.layout(cx);
320        (layout_id, element)
321    }
322
323    pub(crate) fn paint<V: 'static + Render>(
324        _view: &AnyView,
325        element: AnyElement,
326        cx: &mut WindowContext,
327    ) {
328        element.paint(cx);
329    }
330}