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