view.rs

  1use crate::{
  2    AnyBox, AnyElement, AppContext, AvailableSpace, BorrowWindow, Bounds, Component, Element,
  3    ElementId, EntityHandle, EntityId, Flatten, Handle, LayoutId, Pixels, Size, ViewContext,
  4    VisualContext, WeakHandle, WindowContext,
  5};
  6use anyhow::{Context, Result};
  7use parking_lot::Mutex;
  8use std::{
  9    any::Any,
 10    marker::PhantomData,
 11    sync::{Arc, Weak},
 12};
 13
 14pub struct View<V> {
 15    pub(crate) state: Handle<V>,
 16    render: Arc<Mutex<dyn Fn(&mut V, &mut ViewContext<V>) -> AnyElement<V> + Send + 'static>>,
 17}
 18
 19impl<V: 'static> View<V> {
 20    pub fn for_handle<E>(
 21        state: Handle<V>,
 22        render: impl Fn(&mut V, &mut ViewContext<'_, '_, V>) -> E + Send + 'static,
 23    ) -> View<V>
 24    where
 25        E: Component<V>,
 26    {
 27        View {
 28            state,
 29            render: Arc::new(Mutex::new(
 30                move |state: &mut V, cx: &mut ViewContext<'_, '_, V>| render(state, cx).render(),
 31            )),
 32        }
 33    }
 34
 35    pub fn into_any(self) -> AnyView {
 36        AnyView(Arc::new(self))
 37    }
 38
 39    pub fn downgrade(&self) -> WeakView<V> {
 40        WeakView {
 41            state: self.state.downgrade(),
 42            render: Arc::downgrade(&self.render),
 43        }
 44    }
 45
 46    pub fn update<C, R>(
 47        &self,
 48        cx: &mut C,
 49        f: impl FnOnce(&mut V, &mut C::ViewContext<'_, '_, V>) -> R,
 50    ) -> C::Result<R>
 51    where
 52        C: VisualContext,
 53    {
 54        cx.update_view(self, f)
 55    }
 56
 57    pub fn read<'a>(&self, cx: &'a AppContext) -> &'a V {
 58        cx.entities.read(&self.state)
 59    }
 60}
 61
 62impl<V> Clone for View<V> {
 63    fn clone(&self) -> Self {
 64        Self {
 65            state: self.state.clone(),
 66            render: self.render.clone(),
 67        }
 68    }
 69}
 70
 71impl<V: 'static, ParentViewState: 'static> Component<ParentViewState> for View<V> {
 72    fn render(self) -> AnyElement<ParentViewState> {
 73        AnyElement::new(EraseViewState {
 74            view: self,
 75            parent_view_state_type: PhantomData,
 76        })
 77    }
 78}
 79
 80impl<V: 'static> Element<()> for View<V> {
 81    type ElementState = AnyElement<V>;
 82
 83    fn id(&self) -> Option<ElementId> {
 84        Some(ElementId::View(self.state.entity_id))
 85    }
 86
 87    fn initialize(
 88        &mut self,
 89        _: &mut (),
 90        _: Option<Self::ElementState>,
 91        cx: &mut ViewContext<()>,
 92    ) -> Self::ElementState {
 93        self.update(cx, |state, cx| {
 94            let mut any_element = (self.render.lock())(state, cx);
 95            any_element.initialize(state, cx);
 96            any_element
 97        })
 98    }
 99
100    fn layout(
101        &mut self,
102        _: &mut (),
103        element: &mut Self::ElementState,
104        cx: &mut ViewContext<()>,
105    ) -> LayoutId {
106        self.update(cx, |state, cx| element.layout(state, cx))
107    }
108
109    fn paint(
110        &mut self,
111        _: Bounds<Pixels>,
112        _: &mut (),
113        element: &mut Self::ElementState,
114        cx: &mut ViewContext<()>,
115    ) {
116        self.update(cx, |state, cx| element.paint(state, cx))
117    }
118}
119
120impl<T: 'static> EntityHandle<T> for View<T> {
121    type Weak = WeakView<T>;
122
123    fn entity_id(&self) -> EntityId {
124        self.state.entity_id
125    }
126
127    fn downgrade(&self) -> Self::Weak {
128        self.downgrade()
129    }
130
131    fn upgrade_from(weak: &Self::Weak) -> Option<Self>
132    where
133        Self: Sized,
134    {
135        weak.upgrade()
136    }
137}
138
139pub struct WeakView<V> {
140    pub(crate) state: WeakHandle<V>,
141    render: Weak<Mutex<dyn Fn(&mut V, &mut ViewContext<V>) -> AnyElement<V> + Send + 'static>>,
142}
143
144impl<V: 'static> WeakView<V> {
145    pub fn upgrade(&self) -> Option<View<V>> {
146        let state = self.state.upgrade()?;
147        let render = self.render.upgrade()?;
148        Some(View { state, render })
149    }
150
151    pub fn update<C, R>(
152        &self,
153        cx: &mut C,
154        f: impl FnOnce(&mut V, &mut C::ViewContext<'_, '_, V>) -> R,
155    ) -> Result<R>
156    where
157        C: VisualContext,
158        Result<C::Result<R>>: Flatten<R>,
159    {
160        let view = self.upgrade().context("error upgrading view")?;
161        Ok(view.update(cx, f)).flatten()
162    }
163}
164
165impl<V> Clone for WeakView<V> {
166    fn clone(&self) -> Self {
167        Self {
168            state: self.state.clone(),
169            render: self.render.clone(),
170        }
171    }
172}
173
174struct EraseViewState<V, ParentV> {
175    view: View<V>,
176    parent_view_state_type: PhantomData<ParentV>,
177}
178
179unsafe impl<V, ParentV> Send for EraseViewState<V, ParentV> {}
180
181impl<V: 'static, ParentV: 'static> Component<ParentV> for EraseViewState<V, ParentV> {
182    fn render(self) -> AnyElement<ParentV> {
183        AnyElement::new(self)
184    }
185}
186
187impl<V: 'static, ParentV: 'static> Element<ParentV> for EraseViewState<V, ParentV> {
188    type ElementState = AnyBox;
189
190    fn id(&self) -> Option<ElementId> {
191        Element::id(&self.view)
192    }
193
194    fn initialize(
195        &mut self,
196        _: &mut ParentV,
197        _: Option<Self::ElementState>,
198        cx: &mut ViewContext<ParentV>,
199    ) -> Self::ElementState {
200        ViewObject::initialize(&mut self.view, cx)
201    }
202
203    fn layout(
204        &mut self,
205        _: &mut ParentV,
206        element: &mut Self::ElementState,
207        cx: &mut ViewContext<ParentV>,
208    ) -> LayoutId {
209        ViewObject::layout(&mut self.view, element, cx)
210    }
211
212    fn paint(
213        &mut self,
214        bounds: Bounds<Pixels>,
215        _: &mut ParentV,
216        element: &mut Self::ElementState,
217        cx: &mut ViewContext<ParentV>,
218    ) {
219        ViewObject::paint(&mut self.view, bounds, element, cx)
220    }
221}
222
223trait ViewObject: Send + Sync {
224    fn entity_id(&self) -> EntityId;
225    fn initialize(&self, cx: &mut WindowContext) -> AnyBox;
226    fn layout(&self, element: &mut AnyBox, cx: &mut WindowContext) -> LayoutId;
227    fn paint(&self, bounds: Bounds<Pixels>, element: &mut AnyBox, cx: &mut WindowContext);
228    fn as_any(&self) -> &dyn Any;
229}
230
231impl<V: 'static> ViewObject for View<V> {
232    fn entity_id(&self) -> EntityId {
233        self.state.entity_id
234    }
235
236    fn initialize(&self, cx: &mut WindowContext) -> AnyBox {
237        cx.with_element_id(self.state.entity_id, |_global_id, cx| {
238            self.update(cx, |state, cx| {
239                let mut any_element = Box::new((self.render.lock())(state, cx));
240                any_element.initialize(state, cx);
241                any_element as AnyBox
242            })
243        })
244    }
245
246    fn layout(&self, element: &mut AnyBox, cx: &mut WindowContext) -> LayoutId {
247        cx.with_element_id(self.state.entity_id, |_global_id, cx| {
248            self.update(cx, |state, cx| {
249                let element = element.downcast_mut::<AnyElement<V>>().unwrap();
250                element.layout(state, cx)
251            })
252        })
253    }
254
255    fn paint(&self, _: Bounds<Pixels>, element: &mut AnyBox, cx: &mut WindowContext) {
256        cx.with_element_id(self.state.entity_id, |_global_id, cx| {
257            self.update(cx, |state, cx| {
258                let element = element.downcast_mut::<AnyElement<V>>().unwrap();
259                element.paint(state, cx);
260            });
261        });
262    }
263
264    fn as_any(&self) -> &dyn Any {
265        self
266    }
267}
268
269#[derive(Clone)]
270pub struct AnyView(Arc<dyn ViewObject>);
271
272impl AnyView {
273    pub fn downcast<V: 'static>(&self) -> Option<View<V>> {
274        self.0.as_any().downcast_ref().cloned()
275    }
276
277    pub(crate) fn draw(&self, available_space: Size<AvailableSpace>, cx: &mut WindowContext) {
278        let mut rendered_element = self.0.initialize(cx);
279        let layout_id = self.0.layout(&mut rendered_element, cx);
280        cx.window
281            .layout_engine
282            .compute_layout(layout_id, available_space);
283        let bounds = cx.window.layout_engine.layout_bounds(layout_id);
284        self.0.paint(bounds, &mut rendered_element, cx);
285    }
286}
287
288impl<ParentV: 'static> Component<ParentV> for AnyView {
289    fn render(self) -> AnyElement<ParentV> {
290        AnyElement::new(EraseAnyViewState {
291            view: self,
292            parent_view_state_type: PhantomData,
293        })
294    }
295}
296
297impl Element<()> for AnyView {
298    type ElementState = AnyBox;
299
300    fn id(&self) -> Option<crate::ElementId> {
301        Some(ElementId::View(self.0.entity_id()))
302    }
303
304    fn initialize(
305        &mut self,
306        _: &mut (),
307        _: Option<Self::ElementState>,
308        cx: &mut ViewContext<()>,
309    ) -> Self::ElementState {
310        self.0.initialize(cx)
311    }
312
313    fn layout(
314        &mut self,
315        _: &mut (),
316        element: &mut Self::ElementState,
317        cx: &mut ViewContext<()>,
318    ) -> LayoutId {
319        self.0.layout(element, cx)
320    }
321
322    fn paint(
323        &mut self,
324        bounds: Bounds<Pixels>,
325        _: &mut (),
326        element: &mut AnyBox,
327        cx: &mut ViewContext<()>,
328    ) {
329        self.0.paint(bounds, element, cx)
330    }
331}
332
333struct EraseAnyViewState<ParentViewState> {
334    view: AnyView,
335    parent_view_state_type: PhantomData<ParentViewState>,
336}
337
338unsafe impl<ParentV> Send for EraseAnyViewState<ParentV> {}
339
340impl<ParentV: 'static> Component<ParentV> for EraseAnyViewState<ParentV> {
341    fn render(self) -> AnyElement<ParentV> {
342        AnyElement::new(self)
343    }
344}
345
346impl<ParentV: 'static> Element<ParentV> for EraseAnyViewState<ParentV> {
347    type ElementState = AnyBox;
348
349    fn id(&self) -> Option<ElementId> {
350        Element::id(&self.view)
351    }
352
353    fn initialize(
354        &mut self,
355        _: &mut ParentV,
356        _: Option<Self::ElementState>,
357        cx: &mut ViewContext<ParentV>,
358    ) -> Self::ElementState {
359        self.view.0.initialize(cx)
360    }
361
362    fn layout(
363        &mut self,
364        _: &mut ParentV,
365        element: &mut Self::ElementState,
366        cx: &mut ViewContext<ParentV>,
367    ) -> LayoutId {
368        self.view.0.layout(element, cx)
369    }
370
371    fn paint(
372        &mut self,
373        bounds: Bounds<Pixels>,
374        _: &mut ParentV,
375        element: &mut Self::ElementState,
376        cx: &mut ViewContext<ParentV>,
377    ) {
378        self.view.0.paint(bounds, element, cx)
379    }
380}