1use crate::{
2 AnyElement, AnyEntity, AnyWeakEntity, App, AvailableSpace, Bounds, ContentMask, Context,
3 Element, ElementId, Entity, EntityId, GlobalElementId, InspectorElementId, IntoElement,
4 LayoutId, PaintIndex, Pixels, PrepaintStateIndex, Render, RenderOnce, Size, Style,
5 StyleRefinement, TextStyle, WeakEntity,
6};
7use crate::{Empty, Window};
8use anyhow::Result;
9use collections::FxHashSet;
10use refineable::Refineable;
11use std::mem;
12use std::{
13 any::{TypeId, type_name},
14 fmt,
15 ops::Range,
16};
17
18#[derive(Clone, Debug)]
24pub struct AnyView {
25 entity: AnyEntity,
26 render: fn(&AnyView, &mut Window, &mut App) -> AnyElement,
27}
28
29impl<V: Render> From<Entity<V>> for AnyView {
30 fn from(value: Entity<V>) -> Self {
31 AnyView {
32 entity: value.into_any(),
33 render: any_view::render::<V>,
34 }
35 }
36}
37
38impl AnyView {
39 pub fn cached(self, style: StyleRefinement) -> ViewElement<AnyView> {
45 ViewElement::new(self).cached(style)
46 }
47
48 pub fn downgrade(&self) -> AnyWeakView {
50 AnyWeakView {
51 entity: self.entity.downgrade(),
52 render: self.render,
53 }
54 }
55
56 pub fn downcast<T: 'static>(self) -> Result<Entity<T>, Self> {
59 match self.entity.downcast() {
60 Ok(entity) => Ok(entity),
61 Err(entity) => Err(Self {
62 entity,
63 render: self.render,
64 }),
65 }
66 }
67
68 pub fn entity_type(&self) -> TypeId {
70 self.entity.entity_type
71 }
72
73 pub fn entity_id(&self) -> EntityId {
75 self.entity.entity_id()
76 }
77}
78
79impl PartialEq for AnyView {
80 fn eq(&self, other: &Self) -> bool {
81 self.entity == other.entity
82 }
83}
84
85impl Eq for AnyView {}
86
87impl View for AnyView {
91 fn entity_id(&self) -> Option<EntityId> {
92 Some(self.entity.entity_id())
93 }
94
95 fn render(self, window: &mut Window, cx: &mut App) -> impl IntoElement {
96 (self.render)(&self, window, cx)
97 }
98}
99
100impl<V: 'static + Render> IntoElement for Entity<V> {
101 type Element = ViewElement<Entity<V>>;
102
103 fn into_element(self) -> Self::Element {
104 ViewElement::new(self)
105 }
106
107 #[inline(never)]
108 fn into_any_element(self) -> AnyElement {
109 self.into_element().into_any()
110 }
111}
112
113impl IntoElement for AnyView {
114 type Element = ViewElement<AnyView>;
115
116 fn into_element(self) -> Self::Element {
117 ViewElement::new(self)
118 }
119}
120
121pub struct AnyWeakView {
123 entity: AnyWeakEntity,
124 render: fn(&AnyView, &mut Window, &mut App) -> AnyElement,
125}
126
127impl AnyWeakView {
128 pub fn upgrade(&self) -> Option<AnyView> {
130 let entity = self.entity.upgrade()?;
131 Some(AnyView {
132 entity,
133 render: self.render,
134 })
135 }
136}
137
138impl<V: 'static + Render> From<WeakEntity<V>> for AnyWeakView {
139 fn from(view: WeakEntity<V>) -> Self {
140 AnyWeakView {
141 entity: view.into(),
142 render: any_view::render::<V>,
143 }
144 }
145}
146
147impl PartialEq for AnyWeakView {
148 fn eq(&self, other: &Self) -> bool {
149 self.entity == other.entity
150 }
151}
152
153impl std::fmt::Debug for AnyWeakView {
154 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
155 f.debug_struct("AnyWeakView")
156 .field("entity_id", &self.entity.entity_id)
157 .finish_non_exhaustive()
158 }
159}
160
161mod any_view {
162 use crate::{AnyElement, AnyView, App, IntoElement, Render, Window};
163
164 pub(crate) fn render<V: 'static + Render>(
165 view: &AnyView,
166 window: &mut Window,
167 cx: &mut App,
168 ) -> AnyElement {
169 let view = view.clone().downcast::<V>().unwrap();
170 #[cfg(debug_assertions)]
173 window
174 .a11y
175 .view_type_names
176 .insert(view.entity_id(), std::any::type_name::<V>());
177 view.update(cx, |view, cx| view.render(window, cx).into_any_element())
178 }
179}
180
181pub trait View: 'static + Sized {
193 fn entity_id(&self) -> Option<EntityId>;
202
203 fn render(self, window: &mut Window, cx: &mut App) -> impl IntoElement;
205}
206
207impl<T: RenderOnce> View for T {
209 fn entity_id(&self) -> Option<EntityId> {
210 None
211 }
212
213 #[inline]
214 fn render(self, window: &mut Window, cx: &mut App) -> impl IntoElement {
215 RenderOnce::render(self, window, cx)
216 }
217}
218
219impl<T: Render> View for Entity<T> {
221 fn entity_id(&self) -> Option<EntityId> {
222 Some(Entity::entity_id(self))
223 }
224
225 #[inline]
226 fn render(self, window: &mut Window, cx: &mut App) -> impl IntoElement {
227 self.update(cx, |this, cx| {
228 Render::render(this, window, cx).into_any_element()
229 })
230 }
231}
232
233impl<T: Render> Entity<T> {
234 #[track_caller]
242 pub fn cached(self, style: StyleRefinement) -> ViewElement<Entity<T>> {
243 ViewElement::new(self).cached(style)
244 }
245}
246
247#[doc(hidden)]
250pub struct ViewElement<V: View> {
251 view: Option<V>,
252 entity_id: Option<EntityId>,
253 cached_style: Option<StyleRefinement>,
254 #[cfg(debug_assertions)]
255 source: &'static core::panic::Location<'static>,
256}
257
258impl<V: View> ViewElement<V> {
259 #[track_caller]
261 pub fn new(view: V) -> Self {
262 let entity_id = view.entity_id();
263 ViewElement {
264 entity_id,
265 cached_style: None,
266 view: Some(view),
267 #[cfg(debug_assertions)]
268 source: core::panic::Location::caller(),
269 }
270 }
271
272 pub(crate) fn cached(mut self, style: StyleRefinement) -> Self {
282 self.cached_style = Some(style);
283 self
284 }
285}
286
287impl<V: View> IntoElement for ViewElement<V> {
288 type Element = Self;
289
290 fn into_element(self) -> Self::Element {
291 self
292 }
293}
294
295struct ViewElementState {
296 prepaint_range: Range<PrepaintStateIndex>,
297 paint_range: Range<PaintIndex>,
298 cache_key: ViewElementCacheKey,
299 accessed_entities: FxHashSet<EntityId>,
300}
301
302struct ViewElementCacheKey {
303 bounds: Bounds<Pixels>,
304 content_mask: ContentMask<Pixels>,
305 text_style: TextStyle,
306}
307
308impl<V: View> Element for ViewElement<V> {
309 type RequestLayoutState = Option<AnyElement>;
310 type PrepaintState = Option<AnyElement>;
311
312 fn id(&self) -> Option<ElementId> {
313 self.entity_id.map(ElementId::View)
314 }
315
316 fn source_location(&self) -> Option<&'static core::panic::Location<'static>> {
317 #[cfg(debug_assertions)]
318 return Some(self.source);
319
320 #[cfg(not(debug_assertions))]
321 return None;
322 }
323
324 fn request_layout(
325 &mut self,
326 _id: Option<&GlobalElementId>,
327 _inspector_id: Option<&InspectorElementId>,
328 window: &mut Window,
329 cx: &mut App,
330 ) -> (LayoutId, Self::RequestLayoutState) {
331 if let Some(entity_id) = self.entity_id {
332 let view = &mut self.view;
334 request_layout_view(
335 entity_id,
336 self.cached_style.as_ref(),
337 window,
338 cx,
339 &mut |window, cx| view.take().unwrap().render(window, cx).into_any_element(),
340 )
341 } else {
342 request_layout_component(type_name::<V>(), window, cx, &mut |window, cx| {
344 self.view
345 .take()
346 .unwrap()
347 .render(window, cx)
348 .into_any_element()
349 })
350 }
351 }
352
353 fn prepaint(
354 &mut self,
355 global_id: Option<&GlobalElementId>,
356 _inspector_id: Option<&InspectorElementId>,
357 bounds: Bounds<Pixels>,
358 element: &mut Self::RequestLayoutState,
359 window: &mut Window,
360 cx: &mut App,
361 ) -> Option<AnyElement> {
362 if let Some(entity_id) = self.entity_id {
363 prepaint_view(
365 entity_id,
366 global_id,
367 bounds,
368 element,
369 window,
370 cx,
371 &mut |window, cx| {
372 self.view
373 .take()
374 .unwrap()
375 .render(window, cx)
376 .into_any_element()
377 },
378 )
379 } else {
380 prepaint_component(type_name::<V>(), element, window, cx)
382 }
383 }
384
385 fn paint(
386 &mut self,
387 global_id: Option<&GlobalElementId>,
388 _inspector_id: Option<&InspectorElementId>,
389 _bounds: Bounds<Pixels>,
390 _request_layout: &mut Self::RequestLayoutState,
391 element: &mut Self::PrepaintState,
392 window: &mut Window,
393 cx: &mut App,
394 ) {
395 if let Some(entity_id) = self.entity_id {
396 paint_view(
398 entity_id,
399 self.cached_style.is_some(),
400 global_id,
401 element,
402 window,
403 cx,
404 );
405 } else {
406 paint_component(std::any::type_name::<V>(), element, window, cx);
408 }
409 }
410}
411
412pub struct EmptyView;
414
415impl Render for EmptyView {
416 fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
417 Empty
418 }
419}
420
421#[inline(never)]
422fn request_layout_view(
423 entity_id: EntityId,
424 cached_style: Option<&StyleRefinement>,
425 window: &mut Window,
426 cx: &mut App,
427 render: &mut dyn FnMut(&mut Window, &mut App) -> AnyElement,
428) -> (LayoutId, Option<AnyElement>) {
429 window.with_rendered_view(entity_id, |window| {
430 let caching_disabled = window.is_inspector_picking(cx);
431 match cached_style {
432 Some(style) if !caching_disabled => {
433 let mut root_style = Style::default();
434 root_style.refine(style);
435 let layout_id = window.request_layout(root_style, None, cx);
436 (layout_id, None)
437 }
438 _ => {
439 let mut element = render(window, cx);
440 let layout_id = element.request_layout(window, cx);
441 (layout_id, Some(element))
442 }
443 }
444 })
445}
446
447#[inline(never)]
448fn request_layout_component(
449 name: &'static str,
450 window: &mut Window,
451 cx: &mut App,
452 render: &mut dyn FnMut(&mut Window, &mut App) -> AnyElement,
453) -> (LayoutId, Option<AnyElement>) {
454 window.with_id(ElementId::from(name), |window| {
455 let mut element = render(window, cx);
456 let layout_id = element.request_layout(window, cx);
457 (layout_id, Some(element))
458 })
459}
460
461#[inline(never)]
462fn prepaint_view(
463 entity_id: EntityId,
464 global_id: Option<&GlobalElementId>,
465 bounds: Bounds<Pixels>,
466 element: &mut Option<AnyElement>,
467 window: &mut Window,
468 cx: &mut App,
469 render: &mut dyn FnMut(&mut Window, &mut App) -> AnyElement,
470) -> Option<AnyElement> {
471 window.set_view_id(entity_id);
472 window.with_rendered_view(entity_id, |window| {
473 if let Some(mut element) = element.take() {
474 element.prepaint(window, cx);
475 return Some(element);
476 }
477
478 window.with_element_state::<ViewElementState, _>(
479 global_id.unwrap(),
480 |element_state, window| {
481 let content_mask = window.content_mask();
482 let text_style = window.text_style();
483
484 if let Some(mut element_state) = element_state
485 && element_state.cache_key.bounds == bounds
486 && element_state.cache_key.content_mask == content_mask
487 && element_state.cache_key.text_style == text_style
488 && !window.dirty_views.contains(&entity_id)
489 && !window.refreshing
490 {
491 let prepaint_start = window.prepaint_index();
492 window.reuse_prepaint(element_state.prepaint_range.clone());
493 cx.entities
494 .extend_accessed(&element_state.accessed_entities);
495 let prepaint_end = window.prepaint_index();
496 element_state.prepaint_range = prepaint_start..prepaint_end;
497
498 return (None, element_state);
499 }
500
501 let refreshing = mem::replace(&mut window.refreshing, true);
502 let prepaint_start = window.prepaint_index();
503 let (element, accessed_entities) = cx.detect_accessed_entities(|cx| {
504 let mut element = render(window, cx);
505 element.layout_as_root(Size::<AvailableSpace>::from(bounds.size), window, cx);
506 element.prepaint_at(bounds.origin, window, cx);
507 element
508 });
509
510 let prepaint_end = window.prepaint_index();
511 window.refreshing = refreshing;
512
513 (
514 Some(element),
515 ViewElementState {
516 accessed_entities,
517 prepaint_range: prepaint_start..prepaint_end,
518 paint_range: PaintIndex::default()..PaintIndex::default(),
519 cache_key: ViewElementCacheKey {
520 bounds,
521 content_mask,
522 text_style,
523 },
524 },
525 )
526 },
527 )
528 })
529}
530
531#[inline(never)]
532fn prepaint_component(
533 name: &'static str,
534 element: &mut Option<AnyElement>,
535 window: &mut Window,
536 cx: &mut App,
537) -> Option<AnyElement> {
538 window.with_id(ElementId::from(name), |window| {
539 element.as_mut().unwrap().prepaint(window, cx);
540 });
541 Some(element.take().unwrap())
542}
543
544#[inline(never)]
545fn paint_view(
546 entity_id: EntityId,
547 cached: bool,
548 global_id: Option<&GlobalElementId>,
549 element: &mut Option<AnyElement>,
550 window: &mut Window,
551 cx: &mut App,
552) {
553 window.with_rendered_view(entity_id, |window| {
554 let caching_disabled = window.is_inspector_picking(cx);
555 if cached && !caching_disabled {
556 window.with_element_state::<ViewElementState, _>(
557 global_id.unwrap(),
558 |element_state, window| {
559 let mut element_state = element_state.unwrap();
560
561 let paint_start = window.paint_index();
562
563 if let Some(element) = element {
564 let refreshing = mem::replace(&mut window.refreshing, true);
565 element.paint(window, cx);
566 window.refreshing = refreshing;
567 } else {
568 window.reuse_paint(element_state.paint_range.clone());
569 }
570
571 let paint_end = window.paint_index();
572 element_state.paint_range = paint_start..paint_end;
573
574 ((), element_state)
575 },
576 )
577 } else {
578 element.as_mut().unwrap().paint(window, cx);
579 }
580 });
581}
582
583#[inline(never)]
584fn paint_component(
585 name: &'static str,
586 element: &mut Option<AnyElement>,
587 window: &mut Window,
588 cx: &mut App,
589) {
590 window.with_id(ElementId::Name(name.into()), |window| {
591 element.as_mut().unwrap().paint(window, cx);
592 });
593}