@@ -56,21 +56,23 @@ impl HelloWorld {
}))
.when(self.secondary_open, |this| {
this.child(
- // GPUI can't support deferred here yet,
- // it was inside another deferred element.
- anchored()
- .anchor(Corner::TopLeft)
- .snap_to_window_with_margin(px(8.))
- .child(
- popover()
- .child("This is second level Popover")
- .bg(gpui::white())
- .border_color(gpui::blue())
- .on_mouse_down_out(cx.listener(|this, _, _, cx| {
- this.secondary_open = false;
- cx.notify();
- })),
- ),
+ // Now GPUI supports nested deferred!
+ deferred(
+ anchored()
+ .anchor(Corner::TopLeft)
+ .snap_to_window_with_margin(px(8.))
+ .child(
+ popover()
+ .child("This is second level Popover with nested deferred!")
+ .bg(gpui::white())
+ .border_color(gpui::blue())
+ .on_mouse_down_out(cx.listener(|this, _, _, cx| {
+ this.secondary_open = false;
+ cx.notify();
+ })),
+ ),
+ )
+ .priority(2),
)
})
}
@@ -2344,10 +2344,7 @@ impl Window {
#[cfg(any(feature = "inspector", debug_assertions))]
let inspector_element = self.prepaint_inspector(_inspector_width, cx);
- let mut sorted_deferred_draws =
- (0..self.next_frame.deferred_draws.len()).collect::<SmallVec<[_; 8]>>();
- sorted_deferred_draws.sort_by_key(|ix| self.next_frame.deferred_draws[*ix].priority);
- self.prepaint_deferred_draws(&sorted_deferred_draws, cx);
+ self.prepaint_deferred_draws(cx);
let mut prompt_element = None;
let mut active_drag_element = None;
@@ -2376,7 +2373,7 @@ impl Window {
#[cfg(any(feature = "inspector", debug_assertions))]
self.paint_inspector(inspector_element, cx);
- self.paint_deferred_draws(&sorted_deferred_draws, cx);
+ self.paint_deferred_draws(cx);
if let Some(mut prompt_element) = prompt_element {
prompt_element.paint(self, cx);
@@ -2459,25 +2456,40 @@ impl Window {
None
}
- fn prepaint_deferred_draws(&mut self, deferred_draw_indices: &[usize], cx: &mut App) {
+ fn prepaint_deferred_draws(&mut self, cx: &mut App) {
assert_eq!(self.element_id_stack.len(), 0);
- let mut deferred_draws = mem::take(&mut self.next_frame.deferred_draws);
- for deferred_draw_ix in deferred_draw_indices {
- let deferred_draw = &mut deferred_draws[*deferred_draw_ix];
- self.element_id_stack
- .clone_from(&deferred_draw.element_id_stack);
- self.text_style_stack
- .clone_from(&deferred_draw.text_style_stack);
- self.next_frame
- .dispatch_tree
- .set_active_node(deferred_draw.parent_node);
+ let mut completed_draws = Vec::new();
+
+ // Process deferred draws in multiple rounds to support nesting.
+ // Each round processes all current deferred draws, which may produce new ones.
+ let mut depth = 0;
+ loop {
+ // Limit maximum nesting depth to prevent infinite loops.
+ assert!(depth < 10, "Exceeded maximum (10) deferred depth");
+ depth += 1;
+ let deferred_count = self.next_frame.deferred_draws.len();
+ if deferred_count == 0 {
+ break;
+ }
- let prepaint_start = self.prepaint_index();
- let content_mask = deferred_draw.content_mask.clone();
- if let Some(element) = deferred_draw.element.as_mut() {
- self.with_rendered_view(deferred_draw.current_view, |window| {
- window.with_content_mask(content_mask, |window| {
+ // Sort by priority for this round
+ let traversal_order = self.deferred_draw_traversal_order();
+ let mut deferred_draws = mem::take(&mut self.next_frame.deferred_draws);
+
+ for deferred_draw_ix in traversal_order {
+ let deferred_draw = &mut deferred_draws[deferred_draw_ix];
+ self.element_id_stack
+ .clone_from(&deferred_draw.element_id_stack);
+ self.text_style_stack
+ .clone_from(&deferred_draw.text_style_stack);
+ self.next_frame
+ .dispatch_tree
+ .set_active_node(deferred_draw.parent_node);
+
+ let prepaint_start = self.prepaint_index();
+ if let Some(element) = deferred_draw.element.as_mut() {
+ self.with_rendered_view(deferred_draw.current_view, |window| {
window.with_rem_size(Some(deferred_draw.rem_size), |window| {
window.with_absolute_element_offset(
deferred_draw.absolute_offset,
@@ -2486,30 +2498,38 @@ impl Window {
},
);
});
- });
- })
- } else {
- self.reuse_prepaint(deferred_draw.prepaint_range.clone());
+ })
+ } else {
+ self.reuse_prepaint(deferred_draw.prepaint_range.clone());
+ }
+ let prepaint_end = self.prepaint_index();
+ deferred_draw.prepaint_range = prepaint_start..prepaint_end;
}
- let prepaint_end = self.prepaint_index();
- deferred_draw.prepaint_range = prepaint_start..prepaint_end;
+
+ // Save completed draws and continue with newly added ones
+ completed_draws.append(&mut deferred_draws);
+
+ self.element_id_stack.clear();
+ self.text_style_stack.clear();
}
- assert_eq!(
- self.next_frame.deferred_draws.len(),
- 0,
- "cannot call defer_draw during deferred drawing"
- );
- self.next_frame.deferred_draws = deferred_draws;
- self.element_id_stack.clear();
- self.text_style_stack.clear();
+
+ // Restore all completed draws
+ self.next_frame.deferred_draws = completed_draws;
}
- fn paint_deferred_draws(&mut self, deferred_draw_indices: &[usize], cx: &mut App) {
+ fn paint_deferred_draws(&mut self, cx: &mut App) {
assert_eq!(self.element_id_stack.len(), 0);
+ // Paint all deferred draws in priority order.
+ // Since prepaint has already processed nested deferreds, we just paint them all.
+ if self.next_frame.deferred_draws.len() == 0 {
+ return;
+ }
+
+ let traversal_order = self.deferred_draw_traversal_order();
let mut deferred_draws = mem::take(&mut self.next_frame.deferred_draws);
- for deferred_draw_ix in deferred_draw_indices {
- let mut deferred_draw = &mut deferred_draws[*deferred_draw_ix];
+ for deferred_draw_ix in traversal_order {
+ let mut deferred_draw = &mut deferred_draws[deferred_draw_ix];
self.element_id_stack
.clone_from(&deferred_draw.element_id_stack);
self.next_frame
@@ -2536,6 +2556,13 @@ impl Window {
self.element_id_stack.clear();
}
+ fn deferred_draw_traversal_order(&mut self) -> SmallVec<[usize; 8]> {
+ let deferred_count = self.next_frame.deferred_draws.len();
+ let mut sorted_indices = (0..deferred_count).collect::<SmallVec<[_; 8]>>();
+ sorted_indices.sort_by_key(|ix| self.next_frame.deferred_draws[*ix].priority);
+ sorted_indices
+ }
+
pub(crate) fn prepaint_index(&self) -> PrepaintStateIndex {
PrepaintStateIndex {
hitboxes_index: self.next_frame.hitboxes.len(),