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