1use crate::{
2 AnyElement, AnyEntity, AnyWeakEntity, App, Bounds, ContentMask, Context, Element, ElementId,
3 Entity, EntityId, GlobalElementId, InspectorElementId, IntoElement, LayoutId, PaintIndex,
4 Pixels, PrepaintStateIndex, Render, RenderOnce, Style, StyleRefinement, TextStyle, WeakEntity,
5};
6use crate::{Empty, Window};
7use anyhow::Result;
8use collections::FxHashSet;
9use refineable::Refineable;
10use std::mem;
11use std::{any::TypeId, fmt, ops::Range};
12
13#[derive(Clone, Debug)]
19pub struct AnyView {
20 entity: AnyEntity,
21 render: fn(&AnyView, &mut Window, &mut App) -> AnyElement,
22}
23
24impl<V: Render> From<Entity<V>> for AnyView {
25 fn from(value: Entity<V>) -> Self {
26 AnyView {
27 entity: value.into_any(),
28 render: any_view::render::<V>,
29 }
30 }
31}
32
33impl AnyView {
34 pub fn cached(self, style: StyleRefinement) -> ViewElement<AnyView> {
40 ViewElement::new(self).cached(style)
41 }
42
43 pub fn downgrade(&self) -> AnyWeakView {
45 AnyWeakView {
46 entity: self.entity.downgrade(),
47 render: self.render,
48 }
49 }
50
51 pub fn downcast<T: 'static>(self) -> Result<Entity<T>, Self> {
54 match self.entity.downcast() {
55 Ok(entity) => Ok(entity),
56 Err(entity) => Err(Self {
57 entity,
58 render: self.render,
59 }),
60 }
61 }
62
63 pub fn entity_type(&self) -> TypeId {
65 self.entity.entity_type
66 }
67
68 pub fn entity_id(&self) -> EntityId {
70 self.entity.entity_id()
71 }
72}
73
74impl PartialEq for AnyView {
75 fn eq(&self, other: &Self) -> bool {
76 self.entity == other.entity
77 }
78}
79
80impl Eq for AnyView {}
81
82impl View for AnyView {
86 fn entity_id(&self) -> Option<EntityId> {
87 Some(self.entity.entity_id())
88 }
89
90 fn render(self, window: &mut Window, cx: &mut App) -> impl IntoElement {
91 (self.render)(&self, window, cx)
92 }
93}
94
95impl<V: 'static + Render> IntoElement for Entity<V> {
96 type Element = ViewElement<Entity<V>>;
97
98 fn into_element(self) -> Self::Element {
99 ViewElement::new(self)
100 }
101}
102
103impl IntoElement for AnyView {
104 type Element = ViewElement<AnyView>;
105
106 fn into_element(self) -> Self::Element {
107 ViewElement::new(self)
108 }
109}
110
111pub struct AnyWeakView {
113 entity: AnyWeakEntity,
114 render: fn(&AnyView, &mut Window, &mut App) -> AnyElement,
115}
116
117impl AnyWeakView {
118 pub fn upgrade(&self) -> Option<AnyView> {
120 let entity = self.entity.upgrade()?;
121 Some(AnyView {
122 entity,
123 render: self.render,
124 })
125 }
126}
127
128impl<V: 'static + Render> From<WeakEntity<V>> for AnyWeakView {
129 fn from(view: WeakEntity<V>) -> Self {
130 AnyWeakView {
131 entity: view.into(),
132 render: any_view::render::<V>,
133 }
134 }
135}
136
137impl PartialEq for AnyWeakView {
138 fn eq(&self, other: &Self) -> bool {
139 self.entity == other.entity
140 }
141}
142
143impl std::fmt::Debug for AnyWeakView {
144 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
145 f.debug_struct("AnyWeakView")
146 .field("entity_id", &self.entity.entity_id)
147 .finish_non_exhaustive()
148 }
149}
150
151mod any_view {
152 use crate::{AnyElement, AnyView, App, IntoElement, Render, Window};
153
154 pub(crate) fn render<V: 'static + Render>(
155 view: &AnyView,
156 window: &mut Window,
157 cx: &mut App,
158 ) -> AnyElement {
159 let view = view.clone().downcast::<V>().unwrap();
160 #[cfg(debug_assertions)]
163 window
164 .a11y
165 .view_type_names
166 .insert(view.entity_id(), std::any::type_name::<V>());
167 view.update(cx, |view, cx| view.render(window, cx).into_any_element())
168 }
169}
170
171pub trait View: 'static + Sized {
183 fn entity_id(&self) -> Option<EntityId>;
192
193 fn render(self, window: &mut Window, cx: &mut App) -> impl IntoElement;
195}
196
197impl<T: RenderOnce> View for T {
199 fn entity_id(&self) -> Option<EntityId> {
200 None
201 }
202
203 #[inline]
204 fn render(self, window: &mut Window, cx: &mut App) -> impl IntoElement {
205 RenderOnce::render(self, window, cx)
206 }
207}
208
209impl<T: Render> View for Entity<T> {
211 fn entity_id(&self) -> Option<EntityId> {
212 Some(Entity::entity_id(self))
213 }
214
215 #[inline]
216 fn render(self, window: &mut Window, cx: &mut App) -> impl IntoElement {
217 self.update(cx, |this, cx| {
218 Render::render(this, window, cx).into_any_element()
219 })
220 }
221}
222
223impl<T: Render> Entity<T> {
224 #[track_caller]
232 pub fn cached(self, style: StyleRefinement) -> ViewElement<Entity<T>> {
233 ViewElement::new(self).cached(style)
234 }
235}
236
237#[doc(hidden)]
240pub struct ViewElement<V: View> {
241 view: Option<V>,
242 entity_id: Option<EntityId>,
243 cached_style: Option<StyleRefinement>,
244 #[cfg(debug_assertions)]
245 source: &'static core::panic::Location<'static>,
246}
247
248impl<V: View> ViewElement<V> {
249 #[track_caller]
251 pub fn new(view: V) -> Self {
252 let entity_id = view.entity_id();
253 ViewElement {
254 entity_id,
255 cached_style: None,
256 view: Some(view),
257 #[cfg(debug_assertions)]
258 source: core::panic::Location::caller(),
259 }
260 }
261
262 pub(crate) fn cached(mut self, style: StyleRefinement) -> Self {
272 self.cached_style = Some(style);
273 self
274 }
275}
276
277impl<V: View> IntoElement for ViewElement<V> {
278 type Element = Self;
279
280 fn into_element(self) -> Self::Element {
281 self
282 }
283}
284
285struct ViewElementState {
286 prepaint_range: Range<PrepaintStateIndex>,
287 paint_range: Range<PaintIndex>,
288 cache_key: ViewElementCacheKey,
289 accessed_entities: FxHashSet<EntityId>,
290}
291
292struct ViewElementCacheKey {
293 bounds: Bounds<Pixels>,
294 content_mask: ContentMask<Pixels>,
295 text_style: TextStyle,
296}
297
298impl<V: View> Element for ViewElement<V> {
299 type RequestLayoutState = Option<AnyElement>;
300 type PrepaintState = Option<AnyElement>;
301
302 fn id(&self) -> Option<ElementId> {
303 self.entity_id.map(ElementId::View)
304 }
305
306 fn source_location(&self) -> Option<&'static core::panic::Location<'static>> {
307 #[cfg(debug_assertions)]
308 return Some(self.source);
309
310 #[cfg(not(debug_assertions))]
311 return None;
312 }
313
314 fn request_layout(
315 &mut self,
316 _id: Option<&GlobalElementId>,
317 _inspector_id: Option<&InspectorElementId>,
318 window: &mut Window,
319 cx: &mut App,
320 ) -> (LayoutId, Self::RequestLayoutState) {
321 if let Some(entity_id) = self.entity_id {
322 window.with_rendered_view(entity_id, |window| {
324 let caching_disabled = window.is_inspector_picking(cx);
325 match self.cached_style.as_ref() {
326 Some(style) if !caching_disabled => {
327 let mut root_style = Style::default();
328 root_style.refine(style);
329 let layout_id = window.request_layout(root_style, None, cx);
330 (layout_id, None)
331 }
332 _ => {
333 let mut element = self
334 .view
335 .take()
336 .unwrap()
337 .render(window, cx)
338 .into_any_element();
339 let layout_id = element.request_layout(window, cx);
340 (layout_id, Some(element))
341 }
342 }
343 })
344 } else {
345 window.with_id(
347 ElementId::Name(std::any::type_name::<V>().into()),
348 |window| {
349 let mut element = self
350 .view
351 .take()
352 .unwrap()
353 .render(window, cx)
354 .into_any_element();
355 let layout_id = element.request_layout(window, cx);
356 (layout_id, Some(element))
357 },
358 )
359 }
360 }
361
362 fn prepaint(
363 &mut self,
364 global_id: Option<&GlobalElementId>,
365 _inspector_id: Option<&InspectorElementId>,
366 bounds: Bounds<Pixels>,
367 element: &mut Self::RequestLayoutState,
368 window: &mut Window,
369 cx: &mut App,
370 ) -> Option<AnyElement> {
371 if let Some(entity_id) = self.entity_id {
372 window.set_view_id(entity_id);
374 window.with_rendered_view(entity_id, |window| {
375 if let Some(mut element) = element.take() {
376 element.prepaint(window, cx);
377 return Some(element);
378 }
379
380 window.with_element_state::<ViewElementState, _>(
381 global_id.unwrap(),
382 |element_state, window| {
383 let content_mask = window.content_mask();
384 let text_style = window.text_style();
385
386 if let Some(mut element_state) = element_state
387 && element_state.cache_key.bounds == bounds
388 && element_state.cache_key.content_mask == content_mask
389 && element_state.cache_key.text_style == text_style
390 && !window.dirty_views.contains(&entity_id)
391 && !window.refreshing
392 {
393 let prepaint_start = window.prepaint_index();
394 window.reuse_prepaint(element_state.prepaint_range.clone());
395 cx.entities
396 .extend_accessed(&element_state.accessed_entities);
397 let prepaint_end = window.prepaint_index();
398 element_state.prepaint_range = prepaint_start..prepaint_end;
399
400 return (None, element_state);
401 }
402
403 let refreshing = mem::replace(&mut window.refreshing, true);
404 let prepaint_start = window.prepaint_index();
405 let (mut element, accessed_entities) = cx.detect_accessed_entities(|cx| {
406 let mut element = self
407 .view
408 .take()
409 .unwrap()
410 .render(window, cx)
411 .into_any_element();
412 element.layout_as_root(bounds.size.into(), window, cx);
413 element.prepaint_at(bounds.origin, window, cx);
414 element
415 });
416
417 let prepaint_end = window.prepaint_index();
418 window.refreshing = refreshing;
419
420 (
421 Some(element),
422 ViewElementState {
423 accessed_entities,
424 prepaint_range: prepaint_start..prepaint_end,
425 paint_range: PaintIndex::default()..PaintIndex::default(),
426 cache_key: ViewElementCacheKey {
427 bounds,
428 content_mask,
429 text_style,
430 },
431 },
432 )
433 },
434 )
435 })
436 } else {
437 window.with_id(
439 ElementId::Name(std::any::type_name::<V>().into()),
440 |window| {
441 element.as_mut().unwrap().prepaint(window, cx);
442 },
443 );
444 Some(element.take().unwrap())
445 }
446 }
447
448 fn paint(
449 &mut self,
450 global_id: Option<&GlobalElementId>,
451 _inspector_id: Option<&InspectorElementId>,
452 _bounds: Bounds<Pixels>,
453 _request_layout: &mut Self::RequestLayoutState,
454 element: &mut Self::PrepaintState,
455 window: &mut Window,
456 cx: &mut App,
457 ) {
458 if let Some(entity_id) = self.entity_id {
459 window.with_rendered_view(entity_id, |window| {
461 let caching_disabled = window.is_inspector_picking(cx);
462 if self.cached_style.is_some() && !caching_disabled {
463 window.with_element_state::<ViewElementState, _>(
464 global_id.unwrap(),
465 |element_state, window| {
466 let mut element_state = element_state.unwrap();
467
468 let paint_start = window.paint_index();
469
470 if let Some(element) = element {
471 let refreshing = mem::replace(&mut window.refreshing, true);
472 element.paint(window, cx);
473 window.refreshing = refreshing;
474 } else {
475 window.reuse_paint(element_state.paint_range.clone());
476 }
477
478 let paint_end = window.paint_index();
479 element_state.paint_range = paint_start..paint_end;
480
481 ((), element_state)
482 },
483 )
484 } else {
485 element.as_mut().unwrap().paint(window, cx);
486 }
487 });
488 } else {
489 window.with_id(
491 ElementId::Name(std::any::type_name::<V>().into()),
492 |window| {
493 element.as_mut().unwrap().paint(window, cx);
494 },
495 );
496 }
497 }
498}
499
500pub struct EmptyView;
502
503impl Render for EmptyView {
504 fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
505 Empty
506 }
507}