editor: Fix edit prediction popovers painting outside the editor's bounds (#50361)
Deferred draws previously didn't use a content mask, so you could horizontally scroll an EP popover all the way out of the containing pane. This also affects other UI elements that use the deferred draw system; I think in practice it doesn't make much difference because most of those seem to require something in the editor to be hovered, so if you scroll horizontally the element goes away. Release Notes: - Fixed being able to scroll the edit prediction popover out of the containing pane.
This commit is contained in:
1 parent
65e60a53db
commit
904fe6368a
4 files changed
+39
-19
No files matched your search
@@ -9893,7 +9893,14 @@ impl Editor {
|
||||
|
||||
origin.x -= BORDER_WIDTH;
|
||||
|
||||
window.defer_draw(element, origin, 1);
|
||||
window.with_content_mask(
|
||||
Some(gpui::ContentMask {
|
||||
bounds: *text_bounds,
|
||||
}),
|
||||
|window| {
|
||||
window.defer_draw(element, origin, 1, Some(window.content_mask()));
|
||||
},
|
||||
);
|
||||
|
||||
// Do not return an element, since it will already be drawn due to defer_draw.
|
||||
None
|
||||
|
||||
@@ -2863,7 +2863,7 @@ impl EditorElement {
|
||||
}
|
||||
});
|
||||
|
||||
window.defer_draw(element, origin, 2);
|
||||
window.defer_draw(element, origin, 2, None);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5108,7 +5108,7 @@ impl EditorElement {
|
||||
current_position.y -= size.height;
|
||||
}
|
||||
let position = current_position;
|
||||
window.defer_draw(element, current_position, 1);
|
||||
window.defer_draw(element, current_position, 1, None);
|
||||
if !y_flipped {
|
||||
current_position.y += size.height + MENU_GAP;
|
||||
} else {
|
||||
@@ -5211,7 +5211,7 @@ impl EditorElement {
|
||||
// Skip drawing if it doesn't fit anywhere.
|
||||
if let Some((aside, position, size)) = positioned_aside {
|
||||
let aside_bounds = Bounds::new(position, size);
|
||||
window.defer_draw(aside, position, 2);
|
||||
window.defer_draw(aside, position, 2, None);
|
||||
return Some(aside_bounds);
|
||||
}
|
||||
|
||||
@@ -5420,7 +5420,7 @@ impl EditorElement {
|
||||
.on_mouse_move(|_, _, cx| cx.stop_propagation())
|
||||
.into_any_element();
|
||||
occlusion.layout_as_root(size(width, HOVER_POPOVER_GAP).into(), window, cx);
|
||||
window.defer_draw(occlusion, origin, 2);
|
||||
window.defer_draw(occlusion, origin, 2, None);
|
||||
}
|
||||
|
||||
fn place_popovers_above(
|
||||
@@ -5437,7 +5437,7 @@ impl EditorElement {
|
||||
current_y - size.height,
|
||||
);
|
||||
|
||||
window.defer_draw(popover.element, popover_origin, 2);
|
||||
window.defer_draw(popover.element, popover_origin, 2, None);
|
||||
if position != itertools::Position::Last {
|
||||
let origin = point(popover_origin.x, popover_origin.y - HOVER_POPOVER_GAP);
|
||||
draw_occluder(size.width, origin, window, cx);
|
||||
@@ -5459,7 +5459,7 @@ impl EditorElement {
|
||||
let size = popover.size;
|
||||
let popover_origin = point(hovered_point.x + popover.horizontal_offset, current_y);
|
||||
|
||||
window.defer_draw(popover.element, popover_origin, 2);
|
||||
window.defer_draw(popover.element, popover_origin, 2, None);
|
||||
if position != itertools::Position::Last {
|
||||
let origin = point(popover_origin.x, popover_origin.y + size.height);
|
||||
draw_occluder(size.width, origin, window, cx);
|
||||
@@ -5561,7 +5561,7 @@ impl EditorElement {
|
||||
let size = popover.size;
|
||||
let popover_origin = point(origin.x, current_y);
|
||||
|
||||
window.defer_draw(popover.element, popover_origin, 2);
|
||||
window.defer_draw(popover.element, popover_origin, 2, None);
|
||||
if position != itertools::Position::Last {
|
||||
let origin = point(popover_origin.x, popover_origin.y + size.height);
|
||||
draw_occluder(size.width, origin, window, cx);
|
||||
@@ -5893,7 +5893,7 @@ impl EditorElement {
|
||||
})
|
||||
};
|
||||
|
||||
window.defer_draw(element, final_origin, 2);
|
||||
window.defer_draw(element, final_origin, 2, None);
|
||||
}
|
||||
|
||||
fn paint_background(&self, layout: &EditorLayout, window: &mut Window, cx: &mut App) {
|
||||
|
||||
@@ -62,7 +62,7 @@ impl Element for Deferred {
|
||||
) {
|
||||
let child = self.child.take().unwrap();
|
||||
let element_offset = window.element_offset();
|
||||
window.defer_draw(child, element_offset, self.priority)
|
||||
window.defer_draw(child, element_offset, self.priority, None)
|
||||
}
|
||||
|
||||
fn paint(
|
||||
|
||||
@@ -726,6 +726,7 @@ pub(crate) struct DeferredDraw {
|
||||
parent_node: DispatchNodeId,
|
||||
element_id_stack: SmallVec<[ElementId; 32]>,
|
||||
text_style_stack: Vec<TextStyleRefinement>,
|
||||
content_mask: Option<ContentMask<Pixels>>,
|
||||
rem_size: Pixels,
|
||||
element: Option<AnyElement>,
|
||||
absolute_offset: Point<Pixels>,
|
||||
@@ -2429,15 +2430,18 @@ impl Window {
|
||||
.set_active_node(deferred_draw.parent_node);
|
||||
|
||||
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_rem_size(Some(deferred_draw.rem_size), |window| {
|
||||
window.with_absolute_element_offset(
|
||||
deferred_draw.absolute_offset,
|
||||
|window| {
|
||||
element.prepaint(window, cx);
|
||||
},
|
||||
);
|
||||
window.with_content_mask(content_mask, |window| {
|
||||
window.with_rem_size(Some(deferred_draw.rem_size), |window| {
|
||||
window.with_absolute_element_offset(
|
||||
deferred_draw.absolute_offset,
|
||||
|window| {
|
||||
element.prepaint(window, cx);
|
||||
},
|
||||
);
|
||||
});
|
||||
});
|
||||
})
|
||||
} else {
|
||||
@@ -2469,10 +2473,13 @@ impl Window {
|
||||
.set_active_node(deferred_draw.parent_node);
|
||||
|
||||
let paint_start = self.paint_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_rem_size(Some(deferred_draw.rem_size), |window| {
|
||||
element.paint(window, cx);
|
||||
window.with_content_mask(content_mask, |window| {
|
||||
window.with_rem_size(Some(deferred_draw.rem_size), |window| {
|
||||
element.paint(window, cx);
|
||||
});
|
||||
})
|
||||
})
|
||||
} else {
|
||||
@@ -2536,6 +2543,7 @@ impl Window {
|
||||
parent_node: reused_subtree.refresh_node_id(deferred_draw.parent_node),
|
||||
element_id_stack: deferred_draw.element_id_stack.clone(),
|
||||
text_style_stack: deferred_draw.text_style_stack.clone(),
|
||||
content_mask: deferred_draw.content_mask.clone(),
|
||||
rem_size: deferred_draw.rem_size,
|
||||
priority: deferred_draw.priority,
|
||||
element: None,
|
||||
@@ -3019,12 +3027,16 @@ impl Window {
|
||||
/// at a later time. The `priority` parameter determines the drawing order relative to other deferred elements,
|
||||
/// with higher values being drawn on top.
|
||||
///
|
||||
/// When `content_mask` is provided, the deferred element will be clipped to that region during
|
||||
/// both prepaint and paint. When `None`, no additional clipping is applied.
|
||||
///
|
||||
/// This method should only be called as part of the prepaint phase of element drawing.
|
||||
pub fn defer_draw(
|
||||
&mut self,
|
||||
element: AnyElement,
|
||||
absolute_offset: Point<Pixels>,
|
||||
priority: usize,
|
||||
content_mask: Option<ContentMask<Pixels>>,
|
||||
) {
|
||||
self.invalidator.debug_assert_prepaint();
|
||||
let parent_node = self.next_frame.dispatch_tree.active_node_id().unwrap();
|
||||
@@ -3033,6 +3045,7 @@ impl Window {
|
||||
parent_node,
|
||||
element_id_stack: self.element_id_stack.clone(),
|
||||
text_style_stack: self.text_style_stack.clone(),
|
||||
content_mask,
|
||||
rem_size: self.rem_size(),
|
||||
priority,
|
||||
element: Some(element),
|
||||
|
||||
Reference in new issue
Block a user