1use crate::{
2 AnyElement, App, Bounds, Element, GlobalElementId, InspectorElementId, IntoElement, LayoutId,
3 Pixels, Window,
4};
5
6pub fn deferred(child: impl IntoElement) -> Deferred {
8 Deferred {
9 child: Some(child.into_any_element()),
10 priority: 0,
11 }
12}
13
14pub struct Deferred {
17 child: Option<AnyElement>,
18 priority: usize,
19}
20
21impl Deferred {
22 pub fn with_priority(mut self, priority: usize) -> Self {
26 self.priority = priority;
27 self
28 }
29}
30
31impl Element for Deferred {
32 type RequestLayoutState = ();
33 type PrepaintState = ();
34
35 fn id(&self) -> Option<crate::ElementId> {
36 None
37 }
38
39 fn source_location(&self) -> Option<&'static core::panic::Location<'static>> {
40 None
41 }
42
43 fn request_layout(
44 &mut self,
45 _id: Option<&GlobalElementId>,
46 _inspector_id: Option<&InspectorElementId>,
47 window: &mut Window,
48 cx: &mut App,
49 ) -> (LayoutId, ()) {
50 let layout_id = self.child.as_mut().unwrap().request_layout(window, cx);
51 (layout_id, ())
52 }
53
54 fn prepaint(
55 &mut self,
56 _id: Option<&GlobalElementId>,
57 _inspector_id: Option<&InspectorElementId>,
58 _bounds: Bounds<Pixels>,
59 _request_layout: &mut Self::RequestLayoutState,
60 window: &mut Window,
61 _cx: &mut App,
62 ) {
63 let child = self.child.take().unwrap();
64 let element_offset = window.element_offset();
65 window.defer_draw(child, element_offset, self.priority, None)
66 }
67
68 fn paint(
69 &mut self,
70 _id: Option<&GlobalElementId>,
71 _inspector_id: Option<&InspectorElementId>,
72 _bounds: Bounds<Pixels>,
73 _request_layout: &mut Self::RequestLayoutState,
74 _prepaint: &mut Self::PrepaintState,
75 _window: &mut Window,
76 _cx: &mut App,
77 ) {
78 }
79}
80
81impl IntoElement for Deferred {
82 type Element = Self;
83
84 fn into_element(self) -> Self::Element {
85 self
86 }
87}
88
89impl Deferred {
90 pub fn priority(mut self, priority: usize) -> Self {
93 self.priority = priority;
94 self
95 }
96}
97
98#[cfg(test)]
99mod tests {
100 use crate::{
101 Context, Entity, StyleRefinement, TestAppContext, Window, anchored, deferred, div, point,
102 prelude::*, px, size,
103 };
104
105 struct PanelView;
109
110 impl Render for PanelView {
111 fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
112 div().key_context("Panel").size_full().child(
113 deferred(
114 anchored().position(point(px(10.), px(10.))).child(
115 div().key_context("Popover").w(px(200.)).h(px(200.)).child(
116 deferred(
117 anchored().position(point(px(30.), px(30.))).child(
118 div()
119 .key_context("NestedMenu")
120 .debug_selector(|| "NESTED_MENU".into())
121 .w(px(50.))
122 .h(px(50.)),
123 ),
124 )
125 .with_priority(2),
126 ),
127 ),
128 )
129 .with_priority(1),
130 )
131 }
132 }
133
134 struct RootView {
135 panel: Entity<PanelView>,
136 }
137
138 impl Render for RootView {
139 fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
140 div().key_context("Root").size_full().child(
141 self.panel
142 .clone()
143 .cached(StyleRefinement::default().size_full()),
144 )
145 }
146 }
147
148 #[gpui::test]
156 fn test_nested_deferred_draws_with_reused_views(cx: &mut TestAppContext) {
157 let window = cx.open_window(size(px(800.), px(600.)), |_, cx| {
158 let panel = cx.new(|_| PanelView);
159 RootView { panel }
160 });
161 cx.run_until_parked();
162
163 let menu_bounds = window
164 .update(cx, |_, window, _| {
165 window
166 .rendered_frame
167 .debug_bounds
168 .get("NESTED_MENU")
169 .copied()
170 })
171 .unwrap()
172 .expect("NESTED_MENU debug bounds not found");
173 assert_eq!(menu_bounds.size, size(px(50.), px(50.)));
174
175 window.update(cx, |_, _, cx| cx.notify()).unwrap();
179 cx.run_until_parked();
180
181 window.update(cx, |_, _, cx| cx.notify()).unwrap();
184 cx.run_until_parked();
185
186 window
188 .update(cx, |root, _, cx| {
189 root.panel.update(cx, |_, cx| cx.notify());
190 })
191 .unwrap();
192 cx.run_until_parked();
193
194 window
195 .update(cx, |_, window, _| {
196 assert_eq!(window.rendered_frame.deferred_draws.len(), 2);
197 assert!(
198 window
199 .rendered_frame
200 .debug_bounds
201 .contains_key("NESTED_MENU")
202 );
203 })
204 .unwrap();
205 }
206}