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