1use crate::{
2 private::Sealed, AnyElement, AnyModel, AnyWeakModel, AppContext, AvailableSpace, BorrowWindow,
3 Bounds, Component, Element, ElementId, Entity, EntityId, Flatten, FocusHandle, FocusableView,
4 LayoutId, Model, Pixels, Point, 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 pub fn focus_handle(&self, cx: &AppContext) -> FocusHandle
78 where
79 V: FocusableView,
80 {
81 self.read(cx).focus_handle(cx)
82 }
83}
84
85impl<V> Clone for View<V> {
86 fn clone(&self) -> Self {
87 Self {
88 model: self.model.clone(),
89 }
90 }
91}
92
93impl<V> Hash for View<V> {
94 fn hash<H: Hasher>(&self, state: &mut H) {
95 self.model.hash(state);
96 }
97}
98
99impl<V> PartialEq for View<V> {
100 fn eq(&self, other: &Self) -> bool {
101 self.model == other.model
102 }
103}
104
105impl<V> Eq for View<V> {}
106
107impl<V: Render, ParentViewState: 'static> Component<ParentViewState> for View<V> {
108 fn render(self) -> AnyElement<ParentViewState> {
109 AnyElement::new(AnyView::from(self))
110 }
111}
112
113pub struct WeakView<V> {
114 pub(crate) model: WeakModel<V>,
115}
116
117impl<V: 'static> WeakView<V> {
118 pub fn entity_id(&self) -> EntityId {
119 self.model.entity_id
120 }
121
122 pub fn upgrade(&self) -> Option<View<V>> {
123 Entity::upgrade_from(self)
124 }
125
126 pub fn update<C, R>(
127 &self,
128 cx: &mut C,
129 f: impl FnOnce(&mut V, &mut ViewContext<'_, V>) -> R,
130 ) -> Result<R>
131 where
132 C: VisualContext,
133 Result<C::Result<R>>: Flatten<R>,
134 {
135 let view = self.upgrade().context("error upgrading view")?;
136 Ok(view.update(cx, f)).flatten()
137 }
138}
139
140impl<V> Clone for WeakView<V> {
141 fn clone(&self) -> Self {
142 Self {
143 model: self.model.clone(),
144 }
145 }
146}
147
148impl<V> Hash for WeakView<V> {
149 fn hash<H: Hasher>(&self, state: &mut H) {
150 self.model.hash(state);
151 }
152}
153
154impl<V> PartialEq for WeakView<V> {
155 fn eq(&self, other: &Self) -> bool {
156 self.model == other.model
157 }
158}
159
160impl<V> Eq for WeakView<V> {}
161
162#[derive(Clone, Debug)]
163pub struct AnyView {
164 model: AnyModel,
165 layout: fn(&AnyView, &mut WindowContext) -> (LayoutId, Box<dyn Any>),
166 paint: fn(&AnyView, Box<dyn Any>, &mut WindowContext),
167}
168
169impl AnyView {
170 pub fn downgrade(&self) -> AnyWeakView {
171 AnyWeakView {
172 model: self.model.downgrade(),
173 layout: self.layout,
174 paint: self.paint,
175 }
176 }
177
178 pub fn downcast<T: 'static>(self) -> Result<View<T>, Self> {
179 match self.model.downcast() {
180 Ok(model) => Ok(View { model }),
181 Err(model) => Err(Self {
182 model,
183 layout: self.layout,
184 paint: self.paint,
185 }),
186 }
187 }
188
189 pub fn entity_type(&self) -> TypeId {
190 self.model.entity_type
191 }
192
193 pub(crate) fn draw(
194 &self,
195 origin: Point<Pixels>,
196 available_space: Size<AvailableSpace>,
197 cx: &mut WindowContext,
198 ) {
199 cx.with_absolute_element_offset(origin, |cx| {
200 let (layout_id, rendered_element) = (self.layout)(self, cx);
201 cx.window
202 .layout_engine
203 .compute_layout(layout_id, available_space);
204 (self.paint)(self, rendered_element, cx);
205 })
206 }
207}
208
209impl<V: 'static> Component<V> for AnyView {
210 fn render(self) -> AnyElement<V> {
211 AnyElement::new(self)
212 }
213}
214
215impl<V: Render> From<View<V>> for AnyView {
216 fn from(value: View<V>) -> Self {
217 AnyView {
218 model: value.model.into_any(),
219 layout: any_view::layout::<V>,
220 paint: any_view::paint::<V>,
221 }
222 }
223}
224
225impl<ParentViewState: 'static> Element<ParentViewState> for AnyView {
226 type State = Option<Box<dyn Any>>;
227
228 fn element_id(&self) -> Option<ElementId> {
229 Some(self.model.entity_id.into())
230 }
231
232 fn layout(
233 &mut self,
234 _view_state: &mut ParentViewState,
235 _element_state: Option<Self::State>,
236 cx: &mut ViewContext<ParentViewState>,
237 ) -> (LayoutId, Self::State) {
238 let (layout_id, rendered_element) = (self.layout)(self, cx);
239 (layout_id, Some(rendered_element))
240 }
241
242 fn paint(
243 mut self,
244 _bounds: Bounds<Pixels>,
245 _view_state: &mut ParentViewState,
246 rendered_element: &mut Self::State,
247 cx: &mut ViewContext<ParentViewState>,
248 ) {
249 (self.paint)(&mut self, rendered_element.take().unwrap(), cx)
250 }
251}
252
253pub struct AnyWeakView {
254 model: AnyWeakModel,
255 layout: fn(&AnyView, &mut WindowContext) -> (LayoutId, Box<dyn Any>),
256 paint: fn(&AnyView, Box<dyn Any>, &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 State = Option<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::State>,
324 cx: &mut ViewContext<ParentViewState>,
325 ) -> (LayoutId, Self::State) {
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, Some(element))
330 })
331 }
332
333 fn paint(
334 self,
335 _: Bounds<Pixels>,
336 _: &mut ParentViewState,
337 element: &mut Self::State,
338 cx: &mut ViewContext<ParentViewState>,
339 ) {
340 self.view
341 .update(cx, |view, cx| element.take().unwrap().paint(view, cx))
342 }
343}
344
345mod any_view {
346 use crate::{AnyElement, AnyView, BorrowWindow, LayoutId, Render, WindowContext};
347 use std::any::Any;
348
349 pub(crate) fn layout<V: Render>(
350 view: &AnyView,
351 cx: &mut WindowContext,
352 ) -> (LayoutId, Box<dyn Any>) {
353 cx.with_element_id(Some(view.model.entity_id), |cx| {
354 let view = view.clone().downcast::<V>().unwrap();
355 view.update(cx, |view, cx| {
356 let mut element = AnyElement::new(view.render(cx));
357 let layout_id = element.layout(view, cx);
358 (layout_id, Box::new(element) as Box<dyn Any>)
359 })
360 })
361 }
362
363 pub(crate) fn paint<V: Render>(view: &AnyView, element: Box<dyn Any>, cx: &mut WindowContext) {
364 cx.with_element_id(Some(view.model.entity_id), |cx| {
365 let view = view.clone().downcast::<V>().unwrap();
366 let element = element.downcast::<AnyElement<V>>().unwrap();
367 view.update(cx, |view, cx| element.paint(view, cx))
368 })
369 }
370}