view.rs

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