view.rs

  1use crate::{
  2    AnyBox, AnyElement, AvailableSpace, BorrowWindow, Bounds, Component, Element, ElementId,
  3    EntityId, Flatten, Handle, LayoutId, Pixels, Size, ViewContext, VisualContext, WeakHandle,
  4    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
 36impl<V: 'static> View<V> {
 37    pub fn into_any(self) -> AnyView {
 38        AnyView(Arc::new(self))
 39    }
 40
 41    pub fn downgrade(&self) -> WeakView<V> {
 42        WeakView {
 43            state: self.state.downgrade(),
 44            render: Arc::downgrade(&self.render),
 45        }
 46    }
 47}
 48
 49impl<V: 'static> View<V> {
 50    pub fn update<C, R>(
 51        &self,
 52        cx: &mut C,
 53        f: impl FnOnce(&mut V, &mut C::ViewContext<'_, '_, V>) -> R,
 54    ) -> C::Result<R>
 55    where
 56        C: VisualContext,
 57    {
 58        cx.update_view(self, f)
 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
120pub struct WeakView<V> {
121    pub(crate) state: WeakHandle<V>,
122    render: Weak<Mutex<dyn Fn(&mut V, &mut ViewContext<V>) -> AnyElement<V> + Send + 'static>>,
123}
124
125impl<V: 'static> WeakView<V> {
126    pub fn upgrade(&self) -> Option<View<V>> {
127        let state = self.state.upgrade()?;
128        let render = self.render.upgrade()?;
129        Some(View { state, render })
130    }
131
132    pub fn update<C, R>(
133        &self,
134        cx: &mut C,
135        f: impl FnOnce(&mut V, &mut C::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
146impl<V> Clone for WeakView<V> {
147    fn clone(&self) -> Self {
148        Self {
149            state: self.state.clone(),
150            render: self.render.clone(),
151        }
152    }
153}
154
155struct EraseViewState<V, ParentV> {
156    view: View<V>,
157    parent_view_state_type: PhantomData<ParentV>,
158}
159
160unsafe impl<V, ParentV> Send for EraseViewState<V, ParentV> {}
161
162impl<V: 'static, ParentV: 'static> Component<ParentV> for EraseViewState<V, ParentV> {
163    fn render(self) -> AnyElement<ParentV> {
164        AnyElement::new(self)
165    }
166}
167
168impl<V: 'static, ParentV: 'static> Element<ParentV> for EraseViewState<V, ParentV> {
169    type ElementState = AnyBox;
170
171    fn id(&self) -> Option<ElementId> {
172        Element::id(&self.view)
173    }
174
175    fn initialize(
176        &mut self,
177        _: &mut ParentV,
178        _: Option<Self::ElementState>,
179        cx: &mut ViewContext<ParentV>,
180    ) -> Self::ElementState {
181        ViewObject::initialize(&mut self.view, cx)
182    }
183
184    fn layout(
185        &mut self,
186        _: &mut ParentV,
187        element: &mut Self::ElementState,
188        cx: &mut ViewContext<ParentV>,
189    ) -> LayoutId {
190        ViewObject::layout(&mut self.view, element, cx)
191    }
192
193    fn paint(
194        &mut self,
195        bounds: Bounds<Pixels>,
196        _: &mut ParentV,
197        element: &mut Self::ElementState,
198        cx: &mut ViewContext<ParentV>,
199    ) {
200        ViewObject::paint(&mut self.view, bounds, element, cx)
201    }
202}
203
204trait ViewObject: Send + Sync {
205    fn entity_id(&self) -> EntityId;
206    fn initialize(&self, cx: &mut WindowContext) -> AnyBox;
207    fn layout(&self, element: &mut AnyBox, cx: &mut WindowContext) -> LayoutId;
208    fn paint(&self, bounds: Bounds<Pixels>, element: &mut AnyBox, cx: &mut WindowContext);
209    fn as_any(&self) -> &dyn Any;
210}
211
212impl<V: 'static> ViewObject for View<V> {
213    fn entity_id(&self) -> EntityId {
214        self.state.entity_id
215    }
216
217    fn initialize(&self, cx: &mut WindowContext) -> AnyBox {
218        cx.with_element_id(self.state.entity_id, |_global_id, cx| {
219            self.update(cx, |state, cx| {
220                let mut any_element = Box::new((self.render.lock())(state, cx));
221                any_element.initialize(state, cx);
222                any_element as AnyBox
223            })
224        })
225    }
226
227    fn layout(&self, element: &mut AnyBox, cx: &mut WindowContext) -> LayoutId {
228        cx.with_element_id(self.state.entity_id, |_global_id, cx| {
229            self.update(cx, |state, cx| {
230                let element = element.downcast_mut::<AnyElement<V>>().unwrap();
231                element.layout(state, cx)
232            })
233        })
234    }
235
236    fn paint(&self, _: Bounds<Pixels>, element: &mut AnyBox, cx: &mut WindowContext) {
237        cx.with_element_id(self.state.entity_id, |_global_id, cx| {
238            self.update(cx, |state, cx| {
239                let element = element.downcast_mut::<AnyElement<V>>().unwrap();
240                element.paint(state, cx);
241            });
242        });
243    }
244
245    fn as_any(&self) -> &dyn Any {
246        self
247    }
248}
249
250#[derive(Clone)]
251pub struct AnyView(Arc<dyn ViewObject>);
252
253impl AnyView {
254    pub fn downcast<V: 'static>(&self) -> Option<View<V>> {
255        self.0.as_any().downcast_ref().cloned()
256    }
257
258    pub(crate) fn draw(&self, available_space: Size<AvailableSpace>, cx: &mut WindowContext) {
259        let mut rendered_element = self.0.initialize(cx);
260        let layout_id = self.0.layout(&mut rendered_element, cx);
261        cx.window
262            .layout_engine
263            .compute_layout(layout_id, available_space);
264        let bounds = cx.window.layout_engine.layout_bounds(layout_id);
265        self.0.paint(bounds, &mut rendered_element, cx);
266    }
267}
268
269impl<ParentV: 'static> Component<ParentV> for AnyView {
270    fn render(self) -> AnyElement<ParentV> {
271        AnyElement::new(EraseAnyViewState {
272            view: self,
273            parent_view_state_type: PhantomData,
274        })
275    }
276}
277
278impl Element<()> for AnyView {
279    type ElementState = AnyBox;
280
281    fn id(&self) -> Option<crate::ElementId> {
282        Some(ElementId::View(self.0.entity_id()))
283    }
284
285    fn initialize(
286        &mut self,
287        _: &mut (),
288        _: Option<Self::ElementState>,
289        cx: &mut ViewContext<()>,
290    ) -> Self::ElementState {
291        self.0.initialize(cx)
292    }
293
294    fn layout(
295        &mut self,
296        _: &mut (),
297        element: &mut Self::ElementState,
298        cx: &mut ViewContext<()>,
299    ) -> LayoutId {
300        self.0.layout(element, cx)
301    }
302
303    fn paint(
304        &mut self,
305        bounds: Bounds<Pixels>,
306        _: &mut (),
307        element: &mut AnyBox,
308        cx: &mut ViewContext<()>,
309    ) {
310        self.0.paint(bounds, element, cx)
311    }
312}
313
314struct EraseAnyViewState<ParentViewState> {
315    view: AnyView,
316    parent_view_state_type: PhantomData<ParentViewState>,
317}
318
319unsafe impl<ParentV> Send for EraseAnyViewState<ParentV> {}
320
321impl<ParentV: 'static> Component<ParentV> for EraseAnyViewState<ParentV> {
322    fn render(self) -> AnyElement<ParentV> {
323        AnyElement::new(self)
324    }
325}
326
327impl<ParentV: 'static> Element<ParentV> for EraseAnyViewState<ParentV> {
328    type ElementState = AnyBox;
329
330    fn id(&self) -> Option<ElementId> {
331        Element::id(&self.view)
332    }
333
334    fn initialize(
335        &mut self,
336        _: &mut ParentV,
337        _: Option<Self::ElementState>,
338        cx: &mut ViewContext<ParentV>,
339    ) -> Self::ElementState {
340        self.view.0.initialize(cx)
341    }
342
343    fn layout(
344        &mut self,
345        _: &mut ParentV,
346        element: &mut Self::ElementState,
347        cx: &mut ViewContext<ParentV>,
348    ) -> LayoutId {
349        self.view.0.layout(element, cx)
350    }
351
352    fn paint(
353        &mut self,
354        bounds: Bounds<Pixels>,
355        _: &mut ParentV,
356        element: &mut Self::ElementState,
357        cx: &mut ViewContext<ParentV>,
358    ) {
359        self.view.0.paint(bounds, element, cx)
360    }
361}