1use parking_lot::Mutex;
2
3use crate::{
4 AnyBox, AnyElement, BorrowWindow, Bounds, Element, ElementId, EntityId, Handle, IntoAnyElement,
5 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 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
89struct EraseViewState<ViewState: 'static + Send + Sync, ParentViewState> {
90 view: View<ViewState>,
91 parent_view_state_type: PhantomData<ParentViewState>,
92}
93
94impl<ViewState, ParentViewState> IntoAnyElement<ParentViewState>
95 for EraseViewState<ViewState, ParentViewState>
96where
97 ViewState: 'static + Send + Sync,
98 ParentViewState: 'static + Send + Sync,
99{
100 fn into_any(self) -> AnyElement<ParentViewState> {
101 AnyElement::new(self)
102 }
103}
104
105impl<ViewState, ParentViewState> Element for EraseViewState<ViewState, ParentViewState>
106where
107 ViewState: 'static + Send + Sync,
108 ParentViewState: 'static + Send + Sync,
109{
110 type ViewState = ParentViewState;
111 type ElementState = AnyBox;
112
113 fn id(&self) -> Option<crate::ElementId> {
114 Element::id(&self.view)
115 }
116
117 fn layout(
118 &mut self,
119 _: &mut Self::ViewState,
120 _: Option<Self::ElementState>,
121 cx: &mut ViewContext<Self::ViewState>,
122 ) -> (LayoutId, Self::ElementState) {
123 ViewObject::layout(&mut self.view, cx)
124 }
125
126 fn paint(
127 &mut self,
128 bounds: Bounds<Pixels>,
129 _: &mut Self::ViewState,
130 element: &mut Self::ElementState,
131 cx: &mut ViewContext<Self::ViewState>,
132 ) {
133 ViewObject::paint(&mut self.view, bounds, element, cx)
134 }
135}
136
137trait ViewObject: 'static + Send + Sync {
138 fn entity_id(&self) -> EntityId;
139 fn layout(&mut self, cx: &mut WindowContext) -> (LayoutId, AnyBox);
140 fn paint(&mut self, bounds: Bounds<Pixels>, element: &mut AnyBox, cx: &mut WindowContext);
141}
142
143impl<S: Send + Sync + 'static> ViewObject for View<S> {
144 fn entity_id(&self) -> EntityId {
145 self.state.id
146 }
147
148 fn layout(&mut self, cx: &mut WindowContext) -> (LayoutId, AnyBox) {
149 cx.with_element_id(self.entity_id(), |cx| {
150 self.state.update(cx, |state, cx| {
151 let mut element = (self.render)(state, cx);
152 let layout_id = element.layout(state, cx);
153 let element = Box::new(element) as AnyBox;
154 (layout_id, element)
155 })
156 })
157 }
158
159 fn paint(&mut self, _: Bounds<Pixels>, element: &mut AnyBox, cx: &mut WindowContext) {
160 cx.with_element_id(self.entity_id(), |cx| {
161 self.state.update(cx, |state, cx| {
162 let element = element.downcast_mut::<AnyElement<S>>().unwrap();
163 element.paint(state, None, cx);
164 });
165 });
166 }
167}
168
169pub struct AnyView {
170 view: Arc<Mutex<dyn ViewObject>>,
171}
172
173impl<ParentViewState> IntoAnyElement<ParentViewState> for AnyView
174where
175 ParentViewState: 'static + Send + Sync,
176{
177 fn into_any(self) -> AnyElement<ParentViewState> {
178 AnyElement::new(EraseAnyViewState {
179 view: self,
180 parent_view_state_type: PhantomData,
181 })
182 }
183}
184
185impl Element for AnyView {
186 type ViewState = ();
187 type ElementState = AnyBox;
188
189 fn id(&self) -> Option<crate::ElementId> {
190 Some(ElementId::View(self.view.lock().entity_id()))
191 }
192
193 fn layout(
194 &mut self,
195 _: &mut Self::ViewState,
196 _: Option<Self::ElementState>,
197 cx: &mut ViewContext<Self::ViewState>,
198 ) -> (LayoutId, Self::ElementState) {
199 self.view.lock().layout(cx)
200 }
201
202 fn paint(
203 &mut self,
204 bounds: Bounds<Pixels>,
205 _: &mut (),
206 element: &mut AnyBox,
207 cx: &mut ViewContext<Self::ViewState>,
208 ) {
209 self.view.lock().paint(bounds, element, cx)
210 }
211}
212
213struct EraseAnyViewState<ParentViewState> {
214 view: AnyView,
215 parent_view_state_type: PhantomData<ParentViewState>,
216}
217
218impl<ParentViewState> IntoAnyElement<ParentViewState> for EraseAnyViewState<ParentViewState>
219where
220 ParentViewState: 'static + Send + Sync,
221{
222 fn into_any(self) -> AnyElement<ParentViewState> {
223 AnyElement::new(self)
224 }
225}
226
227impl<ParentViewState> Element for EraseAnyViewState<ParentViewState>
228where
229 ParentViewState: 'static + Send + Sync,
230{
231 type ViewState = ParentViewState;
232 type ElementState = AnyBox;
233
234 fn id(&self) -> Option<crate::ElementId> {
235 Element::id(&self.view)
236 }
237
238 fn layout(
239 &mut self,
240 _: &mut Self::ViewState,
241 _: Option<Self::ElementState>,
242 cx: &mut ViewContext<Self::ViewState>,
243 ) -> (LayoutId, Self::ElementState) {
244 self.view.view.lock().layout(cx)
245 }
246
247 fn paint(
248 &mut self,
249 bounds: Bounds<Pixels>,
250 _: &mut Self::ViewState,
251 element: &mut Self::ElementState,
252 cx: &mut ViewContext<Self::ViewState>,
253 ) {
254 self.view.view.lock().paint(bounds, element, cx)
255 }
256}
257
258impl Clone for AnyView {
259 fn clone(&self) -> Self {
260 Self {
261 view: self.view.clone(),
262 }
263 }
264}