1use crate::{
2 private::Sealed, AnyBox, AnyElement, AnyModel, AnyWeakModel, AppContext, AvailableSpace,
3 BorrowWindow, Bounds, Component, Element, ElementId, Entity, EntityId, Flatten, LayoutId,
4 Model, Pixels, Size, ViewContext, VisualContext, WeakModel, WindowContext,
5};
6use anyhow::{Context, Result};
7use std::{
8 any::{Any, TypeId},
9 hash::{Hash, Hasher},
10};
11
12pub trait Render: 'static + Sized {
13 type Element: Element<Self> + 'static;
14
15 fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element;
16}
17
18pub struct View<V> {
19 pub(crate) model: Model<V>,
20}
21
22impl<V> Sealed for View<V> {}
23
24impl<V: 'static> Entity<V> for View<V> {
25 type Weak = WeakView<V>;
26
27 fn entity_id(&self) -> EntityId {
28 self.model.entity_id
29 }
30
31 fn downgrade(&self) -> Self::Weak {
32 WeakView {
33 model: self.model.downgrade(),
34 }
35 }
36
37 fn upgrade_from(weak: &Self::Weak) -> Option<Self>
38 where
39 Self: Sized,
40 {
41 let model = weak.model.upgrade()?;
42 Some(View { model })
43 }
44}
45
46impl<V: 'static> View<V> {
47 /// Convert this strong view reference into a weak view reference.
48 pub fn downgrade(&self) -> WeakView<V> {
49 Entity::downgrade(self)
50 }
51
52 pub fn update<C, R>(
53 &self,
54 cx: &mut C,
55 f: impl FnOnce(&mut V, &mut ViewContext<'_, V>) -> R,
56 ) -> C::Result<R>
57 where
58 C: VisualContext,
59 {
60 cx.update_view(self, f)
61 }
62
63 pub fn read<'a>(&self, cx: &'a AppContext) -> &'a V {
64 self.model.read(cx)
65 }
66
67 pub fn render_with<C>(&self, component: C) -> RenderViewWith<C, V>
68 where
69 C: 'static + Component<V>,
70 {
71 RenderViewWith {
72 view: self.clone(),
73 component: Some(component),
74 }
75 }
76}
77
78impl<V> Clone for View<V> {
79 fn clone(&self) -> Self {
80 Self {
81 model: self.model.clone(),
82 }
83 }
84}
85
86impl<V> Hash for View<V> {
87 fn hash<H: Hasher>(&self, state: &mut H) {
88 self.model.hash(state);
89 }
90}
91
92impl<V> PartialEq for View<V> {
93 fn eq(&self, other: &Self) -> bool {
94 self.model == other.model
95 }
96}
97
98impl<V> Eq for View<V> {}
99
100impl<V: Render, ParentViewState: 'static> Component<ParentViewState> for View<V> {
101 fn render(self) -> AnyElement<ParentViewState> {
102 AnyElement::new(AnyView::from(self))
103 }
104}
105
106pub struct WeakView<V> {
107 pub(crate) model: WeakModel<V>,
108}
109
110impl<V: 'static> WeakView<V> {
111 pub fn entity_id(&self) -> EntityId {
112 self.model.entity_id
113 }
114
115 pub fn upgrade(&self) -> Option<View<V>> {
116 Entity::upgrade_from(self)
117 }
118
119 pub fn update<C, R>(
120 &self,
121 cx: &mut C,
122 f: impl FnOnce(&mut V, &mut ViewContext<'_, V>) -> R,
123 ) -> Result<R>
124 where
125 C: VisualContext,
126 Result<C::Result<R>>: Flatten<R>,
127 {
128 let view = self.upgrade().context("error upgrading view")?;
129 Ok(view.update(cx, f)).flatten()
130 }
131}
132
133impl<V> Clone for WeakView<V> {
134 fn clone(&self) -> Self {
135 Self {
136 model: self.model.clone(),
137 }
138 }
139}
140
141impl<V> Hash for WeakView<V> {
142 fn hash<H: Hasher>(&self, state: &mut H) {
143 self.model.hash(state);
144 }
145}
146
147impl<V> PartialEq for WeakView<V> {
148 fn eq(&self, other: &Self) -> bool {
149 self.model == other.model
150 }
151}
152
153impl<V> Eq for WeakView<V> {}
154
155#[derive(Clone, Debug)]
156pub struct AnyView {
157 model: AnyModel,
158 initialize: fn(&AnyView, &mut WindowContext) -> AnyBox,
159 layout: fn(&AnyView, &mut AnyBox, &mut WindowContext) -> LayoutId,
160 paint: fn(&AnyView, &mut AnyBox, &mut WindowContext),
161}
162
163impl AnyView {
164 pub fn downgrade(&self) -> AnyWeakView {
165 AnyWeakView {
166 model: self.model.downgrade(),
167 initialize: self.initialize,
168 layout: self.layout,
169 paint: self.paint,
170 }
171 }
172
173 pub fn downcast<T: 'static>(self) -> Result<View<T>, Self> {
174 match self.model.downcast() {
175 Ok(model) => Ok(View { model }),
176 Err(model) => Err(Self {
177 model,
178 initialize: self.initialize,
179 layout: self.layout,
180 paint: self.paint,
181 }),
182 }
183 }
184
185 pub fn entity_type(&self) -> TypeId {
186 self.model.entity_type
187 }
188
189 pub(crate) fn draw(&self, available_space: Size<AvailableSpace>, cx: &mut WindowContext) {
190 let mut rendered_element = (self.initialize)(self, cx);
191 let layout_id = (self.layout)(self, &mut rendered_element, cx);
192 cx.window
193 .layout_engine
194 .compute_layout(layout_id, available_space);
195 (self.paint)(self, &mut rendered_element, cx);
196 }
197}
198
199impl<V: 'static> Component<V> for AnyView {
200 fn render(self) -> AnyElement<V> {
201 AnyElement::new(self)
202 }
203}
204
205impl<V: Render> From<View<V>> for AnyView {
206 fn from(value: View<V>) -> Self {
207 AnyView {
208 model: value.model.into_any(),
209 initialize: any_view::initialize::<V>,
210 layout: any_view::layout::<V>,
211 paint: any_view::paint::<V>,
212 }
213 }
214}
215
216impl<ParentViewState: 'static> Element<ParentViewState> for AnyView {
217 type ElementState = Box<dyn Any>;
218
219 fn element_id(&self) -> Option<ElementId> {
220 Some(self.model.entity_id.into())
221 }
222
223 fn initialize(
224 &mut self,
225 _view_state: &mut ParentViewState,
226 _element_state: Option<Self::ElementState>,
227 cx: &mut ViewContext<ParentViewState>,
228 ) -> Self::ElementState {
229 (self.initialize)(self, cx)
230 }
231
232 fn layout(
233 &mut self,
234 _view_state: &mut ParentViewState,
235 rendered_element: &mut Self::ElementState,
236 cx: &mut ViewContext<ParentViewState>,
237 ) -> LayoutId {
238 (self.layout)(self, rendered_element, cx)
239 }
240
241 fn paint(
242 &mut self,
243 _bounds: Bounds<Pixels>,
244 _view_state: &mut ParentViewState,
245 rendered_element: &mut Self::ElementState,
246 cx: &mut ViewContext<ParentViewState>,
247 ) {
248 (self.paint)(self, rendered_element, cx)
249 }
250}
251
252pub struct AnyWeakView {
253 model: AnyWeakModel,
254 initialize: fn(&AnyView, &mut WindowContext) -> AnyBox,
255 layout: fn(&AnyView, &mut AnyBox, &mut WindowContext) -> LayoutId,
256 paint: fn(&AnyView, &mut AnyBox, &mut WindowContext),
257}
258
259impl AnyWeakView {
260 pub fn upgrade(&self) -> Option<AnyView> {
261 let model = self.model.upgrade()?;
262 Some(AnyView {
263 model,
264 initialize: self.initialize,
265 layout: self.layout,
266 paint: self.paint,
267 })
268 }
269}
270
271impl<V: Render> From<WeakView<V>> for AnyWeakView {
272 fn from(view: WeakView<V>) -> Self {
273 Self {
274 model: view.model.into(),
275 initialize: any_view::initialize::<V>,
276 layout: any_view::layout::<V>,
277 paint: any_view::paint::<V>,
278 }
279 }
280}
281
282impl<T, E> Render for T
283where
284 T: 'static + FnMut(&mut WindowContext) -> E,
285 E: 'static + Send + Element<T>,
286{
287 type Element = E;
288
289 fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
290 (self)(cx)
291 }
292}
293
294pub struct RenderViewWith<C, V> {
295 view: View<V>,
296 component: Option<C>,
297}
298
299impl<C, ParentViewState, ViewState> Component<ParentViewState> for RenderViewWith<C, ViewState>
300where
301 C: 'static + Component<ViewState>,
302 ParentViewState: 'static,
303 ViewState: 'static,
304{
305 fn render(self) -> AnyElement<ParentViewState> {
306 AnyElement::new(self)
307 }
308}
309
310impl<C, ParentViewState, ViewState> Element<ParentViewState> for RenderViewWith<C, ViewState>
311where
312 C: 'static + Component<ViewState>,
313 ParentViewState: 'static,
314 ViewState: 'static,
315{
316 type ElementState = AnyElement<ViewState>;
317
318 fn element_id(&self) -> Option<ElementId> {
319 Some(self.view.entity_id().into())
320 }
321
322 fn initialize(
323 &mut self,
324 _: &mut ParentViewState,
325 _: Option<Self::ElementState>,
326 cx: &mut ViewContext<ParentViewState>,
327 ) -> Self::ElementState {
328 cx.with_element_id(Some(self.view.entity_id()), |cx| {
329 self.view.update(cx, |view, cx| {
330 let mut element = self.component.take().unwrap().render();
331 element.initialize(view, cx);
332 element
333 })
334 })
335 }
336
337 fn layout(
338 &mut self,
339 _: &mut ParentViewState,
340 element: &mut Self::ElementState,
341 cx: &mut ViewContext<ParentViewState>,
342 ) -> LayoutId {
343 cx.with_element_id(Some(self.view.entity_id()), |cx| {
344 self.view.update(cx, |view, cx| element.layout(view, cx))
345 })
346 }
347
348 fn paint(
349 &mut self,
350 _: Bounds<Pixels>,
351 _: &mut ParentViewState,
352 element: &mut Self::ElementState,
353 cx: &mut ViewContext<ParentViewState>,
354 ) {
355 cx.with_element_id(Some(self.view.entity_id()), |cx| {
356 self.view.update(cx, |view, cx| element.paint(view, cx))
357 })
358 }
359}
360
361mod any_view {
362 use crate::{AnyElement, AnyView, BorrowWindow, LayoutId, Render, WindowContext};
363 use std::any::Any;
364
365 pub(crate) fn initialize<V: Render>(view: &AnyView, cx: &mut WindowContext) -> Box<dyn Any> {
366 cx.with_element_id(Some(view.model.entity_id), |cx| {
367 let view = view.clone().downcast::<V>().unwrap();
368 let element = view.update(cx, |view, cx| {
369 let mut element = AnyElement::new(view.render(cx));
370 element.initialize(view, cx);
371 element
372 });
373 Box::new(element)
374 })
375 }
376
377 pub(crate) fn layout<V: Render>(
378 view: &AnyView,
379 element: &mut Box<dyn Any>,
380 cx: &mut WindowContext,
381 ) -> LayoutId {
382 cx.with_element_id(Some(view.model.entity_id), |cx| {
383 let view = view.clone().downcast::<V>().unwrap();
384 let element = element.downcast_mut::<AnyElement<V>>().unwrap();
385 view.update(cx, |view, cx| element.layout(view, cx))
386 })
387 }
388
389 pub(crate) fn paint<V: Render>(
390 view: &AnyView,
391 element: &mut Box<dyn Any>,
392 cx: &mut WindowContext,
393 ) {
394 cx.with_element_id(Some(view.model.entity_id), |cx| {
395 let view = view.clone().downcast::<V>().unwrap();
396 let element = element.downcast_mut::<AnyElement<V>>().unwrap();
397 view.update(cx, |view, cx| element.paint(view, cx))
398 })
399 }
400}