1use crate::{
2 AnyElement, AnyEntity, AnyWeakEntity, App, Bounds, ContentMask, Context, Element, ElementId,
3 Entity, EntityId, GlobalElementId, InspectorElementId, IntoElement, LayoutId, PaintIndex,
4 Pixels, PrepaintStateIndex, Render, Style, StyleRefinement, TextStyle, WeakEntity,
5};
6use crate::{Empty, Window};
7use anyhow::Result;
8use collections::FxHashSet;
9use refineable::Refineable;
10use std::mem;
11use std::rc::Rc;
12use std::{any::TypeId, fmt, ops::Range};
13
14struct AnyViewState {
15 prepaint_range: Range<PrepaintStateIndex>,
16 paint_range: Range<PaintIndex>,
17 cache_key: ViewCacheKey,
18 accessed_entities: FxHashSet<EntityId>,
19}
20
21#[derive(Default)]
22struct ViewCacheKey {
23 bounds: Bounds<Pixels>,
24 content_mask: ContentMask<Pixels>,
25 text_style: TextStyle,
26 opacity: f32,
27}
28
29impl<V: Render> Element for Entity<V> {
30 type RequestLayoutState = AnyElement;
31 type PrepaintState = ();
32
33 fn id(&self) -> Option<ElementId> {
34 Some(ElementId::View(self.entity_id()))
35 }
36
37 fn source_location(&self) -> Option<&'static std::panic::Location<'static>> {
38 None
39 }
40
41 fn request_layout(
42 &mut self,
43 _id: Option<&GlobalElementId>,
44 _inspector_id: Option<&InspectorElementId>,
45 window: &mut Window,
46 cx: &mut App,
47 ) -> (LayoutId, Self::RequestLayoutState) {
48 let mut element = self.update(cx, |view, cx| view.render(window, cx).into_any_element());
49 let layout_id = window.with_rendered_view(self.entity_id(), |window| {
50 element.request_layout(window, cx)
51 });
52 (layout_id, element)
53 }
54
55 fn prepaint(
56 &mut self,
57 _id: Option<&GlobalElementId>,
58 _inspector_id: Option<&InspectorElementId>,
59 _: Bounds<Pixels>,
60 element: &mut Self::RequestLayoutState,
61 window: &mut Window,
62 cx: &mut App,
63 ) {
64 window.set_view_id(self.entity_id());
65 window.with_rendered_view(self.entity_id(), |window| element.prepaint(window, cx));
66 }
67
68 fn paint(
69 &mut self,
70 _id: Option<&GlobalElementId>,
71 _inspector_id: Option<&InspectorElementId>,
72 _: Bounds<Pixels>,
73 element: &mut Self::RequestLayoutState,
74 _: &mut Self::PrepaintState,
75 window: &mut Window,
76 cx: &mut App,
77 ) {
78 window.with_rendered_view(self.entity_id(), |window| element.paint(window, cx));
79 }
80}
81
82#[derive(Clone, Debug)]
84pub struct AnyView {
85 entity: AnyEntity,
86 render: fn(&AnyView, &mut Window, &mut App) -> AnyElement,
87 cached_style: Option<Rc<StyleRefinement>>,
88}
89
90impl<V: Render> From<Entity<V>> for AnyView {
91 fn from(value: Entity<V>) -> Self {
92 AnyView {
93 entity: value.into_any(),
94 render: any_view::render::<V>,
95 cached_style: None,
96 }
97 }
98}
99
100impl AnyView {
101 pub fn cached(mut self, style: StyleRefinement) -> Self {
105 self.cached_style = Some(style.into());
106 self
107 }
108
109 pub fn downgrade(&self) -> AnyWeakView {
111 AnyWeakView {
112 entity: self.entity.downgrade(),
113 render: self.render,
114 }
115 }
116
117 pub fn downcast<T: 'static>(self) -> Result<Entity<T>, Self> {
120 match self.entity.downcast() {
121 Ok(entity) => Ok(entity),
122 Err(entity) => Err(Self {
123 entity,
124 render: self.render,
125 cached_style: self.cached_style,
126 }),
127 }
128 }
129
130 pub fn entity_type(&self) -> TypeId {
132 self.entity.entity_type
133 }
134
135 pub fn entity_id(&self) -> EntityId {
137 self.entity.entity_id()
138 }
139}
140
141impl PartialEq for AnyView {
142 fn eq(&self, other: &Self) -> bool {
143 self.entity == other.entity
144 }
145}
146
147impl Eq for AnyView {}
148
149impl Element for AnyView {
150 type RequestLayoutState = Option<AnyElement>;
151 type PrepaintState = Option<AnyElement>;
152
153 fn id(&self) -> Option<ElementId> {
154 Some(ElementId::View(self.entity_id()))
155 }
156
157 fn source_location(&self) -> Option<&'static core::panic::Location<'static>> {
158 None
159 }
160
161 fn request_layout(
162 &mut self,
163 _id: Option<&GlobalElementId>,
164 _inspector_id: Option<&InspectorElementId>,
165 window: &mut Window,
166 cx: &mut App,
167 ) -> (LayoutId, Self::RequestLayoutState) {
168 window.with_rendered_view(self.entity_id(), |window| {
169 let caching_disabled = window.is_inspector_picking(cx);
171 match self.cached_style.as_ref() {
172 Some(style) if !caching_disabled => {
173 let mut root_style = Style::default();
174 root_style.refine(style);
175 let layout_id = window.request_layout(root_style, None, cx);
176 (layout_id, None)
177 }
178 _ => {
179 let mut element = (self.render)(self, window, cx);
180 let layout_id = element.request_layout(window, cx);
181 (layout_id, Some(element))
182 }
183 }
184 })
185 }
186
187 fn prepaint(
188 &mut self,
189 global_id: Option<&GlobalElementId>,
190 _inspector_id: Option<&InspectorElementId>,
191 bounds: Bounds<Pixels>,
192 element: &mut Self::RequestLayoutState,
193 window: &mut Window,
194 cx: &mut App,
195 ) -> Option<AnyElement> {
196 window.set_view_id(self.entity_id());
197 window.with_rendered_view(self.entity_id(), |window| {
198 if let Some(mut element) = element.take() {
199 element.prepaint(window, cx);
200 return Some(element);
201 }
202
203 window.with_element_state::<AnyViewState, _>(
204 global_id.unwrap(),
205 |element_state, window| {
206 let content_mask = window.content_mask();
207 let text_style = window.text_style();
208 let opacity = window.element_opacity();
209
210 if let Some(mut element_state) = element_state
213 && element_state.cache_key.bounds == bounds
214 && element_state.cache_key.content_mask == content_mask
215 && element_state.cache_key.text_style == text_style
216 && element_state.cache_key.opacity.to_bits() == opacity.to_bits()
217 && !window.dirty_views.contains(&self.entity_id())
218 && !window.refreshing
219 {
220 let prepaint_start = window.prepaint_index();
221 window.reuse_prepaint(element_state.prepaint_range.clone());
222 cx.entities
223 .extend_accessed(&element_state.accessed_entities);
224 let prepaint_end = window.prepaint_index();
225 element_state.prepaint_range = prepaint_start..prepaint_end;
226
227 return (None, element_state);
228 }
229
230 let refreshing = mem::replace(&mut window.refreshing, true);
231 let prepaint_start = window.prepaint_index();
232 let (mut element, accessed_entities) = cx.detect_accessed_entities(|cx| {
233 let mut element = (self.render)(self, window, cx);
234 element.layout_as_root(bounds.size.into(), window, cx);
235 element.prepaint_at(bounds.origin, window, cx);
236 element
237 });
238
239 let prepaint_end = window.prepaint_index();
240 window.refreshing = refreshing;
241
242 (
243 Some(element),
244 AnyViewState {
245 accessed_entities,
246 prepaint_range: prepaint_start..prepaint_end,
247 paint_range: PaintIndex::default()..PaintIndex::default(),
248 cache_key: ViewCacheKey {
249 bounds,
250 content_mask,
251 text_style,
252 opacity,
253 },
254 },
255 )
256 },
257 )
258 })
259 }
260
261 fn paint(
262 &mut self,
263 global_id: Option<&GlobalElementId>,
264 _inspector_id: Option<&InspectorElementId>,
265 _bounds: Bounds<Pixels>,
266 _: &mut Self::RequestLayoutState,
267 element: &mut Self::PrepaintState,
268 window: &mut Window,
269 cx: &mut App,
270 ) {
271 window.with_rendered_view(self.entity_id(), |window| {
272 let caching_disabled = window.is_inspector_picking(cx);
273 if self.cached_style.is_some() && !caching_disabled {
274 window.with_element_state::<AnyViewState, _>(
275 global_id.unwrap(),
276 |element_state, window| {
277 let mut element_state = element_state.unwrap();
278
279 let paint_start = window.paint_index();
280 let opacity = window.element_opacity();
281
282 if let Some(element) = element {
288 let refreshing = mem::replace(&mut window.refreshing, true);
289 element.paint(window, cx);
290 window.refreshing = refreshing;
291 element_state.cache_key.opacity = opacity;
292 } else {
293 window.reuse_paint(element_state.paint_range.clone());
294 if element_state.cache_key.opacity.to_bits() != opacity.to_bits() {
295 window.request_animation_frame();
296 }
297 }
298
299 let paint_end = window.paint_index();
300 element_state.paint_range = paint_start..paint_end;
301
302 ((), element_state)
303 },
304 )
305 } else {
306 element.as_mut().unwrap().paint(window, cx);
307 }
308 });
309 }
310}
311
312impl<V: 'static + Render> IntoElement for Entity<V> {
313 type Element = Entity<V>;
314
315 fn into_element(self) -> Self::Element {
316 self
317 }
318}
319
320impl IntoElement for AnyView {
321 type Element = Self;
322
323 fn into_element(self) -> Self::Element {
324 self
325 }
326}
327
328pub struct AnyWeakView {
330 entity: AnyWeakEntity,
331 render: fn(&AnyView, &mut Window, &mut App) -> AnyElement,
332}
333
334impl AnyWeakView {
335 pub fn upgrade(&self) -> Option<AnyView> {
337 let entity = self.entity.upgrade()?;
338 Some(AnyView {
339 entity,
340 render: self.render,
341 cached_style: None,
342 })
343 }
344}
345
346impl<V: 'static + Render> From<WeakEntity<V>> for AnyWeakView {
347 fn from(view: WeakEntity<V>) -> Self {
348 AnyWeakView {
349 entity: view.into(),
350 render: any_view::render::<V>,
351 }
352 }
353}
354
355impl PartialEq for AnyWeakView {
356 fn eq(&self, other: &Self) -> bool {
357 self.entity == other.entity
358 }
359}
360
361impl std::fmt::Debug for AnyWeakView {
362 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
363 f.debug_struct("AnyWeakView")
364 .field("entity_id", &self.entity.entity_id)
365 .finish_non_exhaustive()
366 }
367}
368
369mod any_view {
370 use crate::{AnyElement, AnyView, App, IntoElement, Render, Window};
371
372 pub(crate) fn render<V: 'static + Render>(
373 view: &AnyView,
374 window: &mut Window,
375 cx: &mut App,
376 ) -> AnyElement {
377 let view = view.clone().downcast::<V>().unwrap();
378 view.update(cx, |view, cx| view.render(window, cx).into_any_element())
379 }
380}
381
382pub struct EmptyView;
384
385impl Render for EmptyView {
386 fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
387 Empty
388 }
389}