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}