view.rs

  1use parking_lot::Mutex;
  2
  3use crate::{
  4    AnyBox, AnyElement, BorrowWindow, Bounds, Element, ElementId, EntityId, Handle,
  5    IdentifiedElement, IntoAnyElement, LayoutId, Pixels, ViewContext, WindowContext,
  6};
  7use std::{marker::PhantomData, sync::Arc};
  8
  9pub struct View<S: Send + Sync> {
 10    state: Handle<S>,
 11    render: Arc<dyn Fn(&mut S, &mut ViewContext<S>) -> AnyElement<S> + Send + Sync + 'static>,
 12}
 13
 14impl<S: 'static + Send + Sync> View<S> {
 15    pub fn into_any(self) -> AnyView {
 16        AnyView {
 17            view: Arc::new(Mutex::new(self)),
 18        }
 19    }
 20}
 21
 22impl<S: Send + Sync> Clone for View<S> {
 23    fn clone(&self) -> Self {
 24        Self {
 25            state: self.state.clone(),
 26            render: self.render.clone(),
 27        }
 28    }
 29}
 30
 31pub fn view<S, E>(
 32    state: Handle<S>,
 33    render: impl Fn(&mut S, &mut ViewContext<S>) -> E + Send + Sync + 'static,
 34) -> View<S>
 35where
 36    E: IntoAnyElement<S>,
 37    S: 'static + Send + Sync,
 38{
 39    View {
 40        state,
 41        render: Arc::new(move |state, cx| render(state, cx).into_any()),
 42    }
 43}
 44
 45impl<S: 'static + Send + Sync, ParentViewState: 'static + Send + Sync>
 46    IntoAnyElement<ParentViewState> for View<S>
 47{
 48    fn into_any(self) -> AnyElement<ParentViewState> {
 49        AnyElement::new(EraseViewState {
 50            view: self,
 51            parent_view_state_type: PhantomData,
 52        })
 53    }
 54}
 55
 56impl<S: 'static + Send + Sync> Element for View<S> {
 57    type ViewState = ();
 58    type ElementState = AnyElement<S>;
 59
 60    fn element_id(&self) -> Option<crate::ElementId> {
 61        Some(ElementId::View(self.state.id))
 62    }
 63
 64    fn layout(
 65        &mut self,
 66        _: &mut Self::ViewState,
 67        _: Option<Self::ElementState>,
 68        cx: &mut ViewContext<Self::ViewState>,
 69    ) -> (LayoutId, Self::ElementState) {
 70        self.state.update(cx, |state, cx| {
 71            let mut element = (self.render)(state, cx);
 72            let layout_id = element.layout(state, cx);
 73            (layout_id, element)
 74        })
 75    }
 76
 77    fn paint(
 78        &mut self,
 79        _: Bounds<Pixels>,
 80        _: &mut Self::ViewState,
 81        element: &mut Self::ElementState,
 82        cx: &mut ViewContext<Self::ViewState>,
 83    ) {
 84        self.state
 85            .update(cx, |state, cx| element.paint(state, None, cx))
 86    }
 87}
 88
 89impl<S: Send + Sync + 'static> IdentifiedElement for View<S> {}
 90
 91struct EraseViewState<ViewState: 'static + Send + Sync, ParentViewState> {
 92    view: View<ViewState>,
 93    parent_view_state_type: PhantomData<ParentViewState>,
 94}
 95
 96impl<ViewState, ParentViewState> IntoAnyElement<ParentViewState>
 97    for EraseViewState<ViewState, ParentViewState>
 98where
 99    ViewState: 'static + Send + Sync,
100    ParentViewState: 'static + Send + Sync,
101{
102    fn into_any(self) -> AnyElement<ParentViewState> {
103        AnyElement::new(self)
104    }
105}
106
107impl<ViewState, ParentViewState> Element for EraseViewState<ViewState, ParentViewState>
108where
109    ViewState: 'static + Send + Sync,
110    ParentViewState: 'static + Send + Sync,
111{
112    type ViewState = ParentViewState;
113    type ElementState = AnyBox;
114
115    fn element_id(&self) -> Option<crate::ElementId> {
116        Element::element_id(&self.view)
117    }
118
119    fn layout(
120        &mut self,
121        _: &mut Self::ViewState,
122        _: Option<Self::ElementState>,
123        cx: &mut ViewContext<Self::ViewState>,
124    ) -> (LayoutId, Self::ElementState) {
125        ViewObject::layout(&mut self.view, cx)
126    }
127
128    fn paint(
129        &mut self,
130        bounds: Bounds<Pixels>,
131        _: &mut Self::ViewState,
132        element: &mut Self::ElementState,
133        cx: &mut ViewContext<Self::ViewState>,
134    ) {
135        ViewObject::paint(&mut self.view, bounds, element, cx)
136    }
137}
138
139trait ViewObject: 'static + Send + Sync {
140    fn entity_id(&self) -> EntityId;
141    fn layout(&mut self, cx: &mut WindowContext) -> (LayoutId, AnyBox);
142    fn paint(&mut self, bounds: Bounds<Pixels>, element: &mut AnyBox, cx: &mut WindowContext);
143}
144
145impl<S: Send + Sync + 'static> ViewObject for View<S> {
146    fn entity_id(&self) -> EntityId {
147        self.state.id
148    }
149
150    fn layout(&mut self, cx: &mut WindowContext) -> (LayoutId, AnyBox) {
151        cx.with_element_id(IdentifiedElement::element_id(self), |cx| {
152            self.state.update(cx, |state, cx| {
153                let mut element = (self.render)(state, cx);
154                let layout_id = element.layout(state, cx);
155                let element = Box::new(element) as AnyBox;
156                (layout_id, element)
157            })
158        })
159    }
160
161    fn paint(&mut self, _: Bounds<Pixels>, element: &mut AnyBox, cx: &mut WindowContext) {
162        cx.with_element_id(IdentifiedElement::element_id(self), |cx| {
163            self.state.update(cx, |state, cx| {
164                let element = element.downcast_mut::<AnyElement<S>>().unwrap();
165                element.paint(state, None, cx);
166            });
167        });
168    }
169}
170
171pub struct AnyView {
172    view: Arc<Mutex<dyn ViewObject>>,
173}
174
175impl<ParentViewState> IntoAnyElement<ParentViewState> for AnyView
176where
177    ParentViewState: 'static + Send + Sync,
178{
179    fn into_any(self) -> AnyElement<ParentViewState> {
180        AnyElement::new(EraseAnyViewState {
181            view: self,
182            parent_view_state_type: PhantomData,
183        })
184    }
185}
186
187impl Element for AnyView {
188    type ViewState = ();
189    type ElementState = AnyBox;
190
191    fn element_id(&self) -> Option<crate::ElementId> {
192        Some(ElementId::View(self.view.lock().entity_id()))
193    }
194
195    fn layout(
196        &mut self,
197        _: &mut Self::ViewState,
198        _: Option<Self::ElementState>,
199        cx: &mut ViewContext<Self::ViewState>,
200    ) -> (LayoutId, Self::ElementState) {
201        self.view.lock().layout(cx)
202    }
203
204    fn paint(
205        &mut self,
206        bounds: Bounds<Pixels>,
207        _: &mut (),
208        element: &mut AnyBox,
209        cx: &mut ViewContext<Self::ViewState>,
210    ) {
211        self.view.lock().paint(bounds, element, cx)
212    }
213}
214
215struct EraseAnyViewState<ParentViewState> {
216    view: AnyView,
217    parent_view_state_type: PhantomData<ParentViewState>,
218}
219
220impl<ParentViewState> IntoAnyElement<ParentViewState> for EraseAnyViewState<ParentViewState>
221where
222    ParentViewState: 'static + Send + Sync,
223{
224    fn into_any(self) -> AnyElement<ParentViewState> {
225        AnyElement::new(self)
226    }
227}
228
229impl<ParentViewState> Element for EraseAnyViewState<ParentViewState>
230where
231    ParentViewState: 'static + Send + Sync,
232{
233    type ViewState = ParentViewState;
234    type ElementState = AnyBox;
235
236    fn element_id(&self) -> Option<crate::ElementId> {
237        Element::element_id(&self.view)
238    }
239
240    fn layout(
241        &mut self,
242        _: &mut Self::ViewState,
243        _: Option<Self::ElementState>,
244        cx: &mut ViewContext<Self::ViewState>,
245    ) -> (LayoutId, Self::ElementState) {
246        self.view.view.lock().layout(cx)
247    }
248
249    fn paint(
250        &mut self,
251        bounds: Bounds<Pixels>,
252        _: &mut Self::ViewState,
253        element: &mut Self::ElementState,
254        cx: &mut ViewContext<Self::ViewState>,
255    ) {
256        self.view.view.lock().paint(bounds, element, cx)
257    }
258}
259
260impl Clone for AnyView {
261    fn clone(&self) -> Self {
262        Self {
263            view: self.view.clone(),
264        }
265    }
266}