Ensure editor elements invalidate their parent views on notify
Co-Authored-By: Nathan Sobo <nathan@zed.dev> Co-Authored-By: Conrad Irwin <conrad@zed.dev>
This commit is contained in:
parent
a32ad3f907
commit
817b641c17
2 changed files with 124 additions and 109 deletions
|
@ -26,11 +26,11 @@ use git::diff::DiffHunkStatus;
|
||||||
use gpui::{
|
use gpui::{
|
||||||
div, fill, outline, overlay, point, px, quad, relative, size, transparent_black, Action,
|
div, fill, outline, overlay, point, px, quad, relative, size, transparent_black, Action,
|
||||||
AnchorCorner, AnyElement, AvailableSpace, BorrowWindow, Bounds, ContentMask, Corners,
|
AnchorCorner, AnyElement, AvailableSpace, BorrowWindow, Bounds, ContentMask, Corners,
|
||||||
CursorStyle, DispatchPhase, Edges, Element, ElementInputHandler, Hsla, InteractiveBounds,
|
CursorStyle, DispatchPhase, Edges, Element, ElementInputHandler, Entity, Hsla,
|
||||||
InteractiveElement, IntoElement, ModifiersChangedEvent, MouseButton, MouseDownEvent,
|
InteractiveBounds, InteractiveElement, IntoElement, ModifiersChangedEvent, MouseButton,
|
||||||
MouseMoveEvent, MouseUpEvent, ParentElement, Pixels, ScrollDelta, ScrollWheelEvent, ShapedLine,
|
MouseDownEvent, MouseMoveEvent, MouseUpEvent, ParentElement, Pixels, ScrollDelta,
|
||||||
SharedString, Size, StackingOrder, StatefulInteractiveElement, Style, Styled, TextRun,
|
ScrollWheelEvent, ShapedLine, SharedString, Size, StackingOrder, StatefulInteractiveElement,
|
||||||
TextStyle, View, ViewContext, WindowContext,
|
Style, Styled, TextRun, TextStyle, View, ViewContext, WindowContext,
|
||||||
};
|
};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use language::language_settings::ShowWhitespaceSetting;
|
use language::language_settings::ShowWhitespaceSetting;
|
||||||
|
@ -2801,44 +2801,49 @@ impl Element for EditorElement {
|
||||||
_element_state: Option<Self::State>,
|
_element_state: Option<Self::State>,
|
||||||
cx: &mut gpui::WindowContext,
|
cx: &mut gpui::WindowContext,
|
||||||
) -> (gpui::LayoutId, Self::State) {
|
) -> (gpui::LayoutId, Self::State) {
|
||||||
self.editor.update(cx, |editor, cx| {
|
cx.with_view_id(self.editor.entity_id(), |cx| {
|
||||||
editor.set_style(self.style.clone(), cx);
|
self.editor.update(cx, |editor, cx| {
|
||||||
|
editor.set_style(self.style.clone(), cx);
|
||||||
|
|
||||||
let layout_id = match editor.mode {
|
let layout_id = match editor.mode {
|
||||||
EditorMode::SingleLine => {
|
EditorMode::SingleLine => {
|
||||||
let rem_size = cx.rem_size();
|
let rem_size = cx.rem_size();
|
||||||
let mut style = Style::default();
|
let mut style = Style::default();
|
||||||
style.size.width = relative(1.).into();
|
style.size.width = relative(1.).into();
|
||||||
style.size.height = self.style.text.line_height_in_pixels(rem_size).into();
|
style.size.height = self.style.text.line_height_in_pixels(rem_size).into();
|
||||||
cx.request_layout(&style, None)
|
cx.request_layout(&style, None)
|
||||||
}
|
}
|
||||||
EditorMode::AutoHeight { max_lines } => {
|
EditorMode::AutoHeight { max_lines } => {
|
||||||
let editor_handle = cx.view().clone();
|
let editor_handle = cx.view().clone();
|
||||||
let max_line_number_width =
|
let max_line_number_width =
|
||||||
self.max_line_number_width(&editor.snapshot(cx), cx);
|
self.max_line_number_width(&editor.snapshot(cx), cx);
|
||||||
cx.request_measured_layout(Style::default(), move |known_dimensions, _, cx| {
|
cx.request_measured_layout(
|
||||||
editor_handle
|
Style::default(),
|
||||||
.update(cx, |editor, cx| {
|
move |known_dimensions, _, cx| {
|
||||||
compute_auto_height_layout(
|
editor_handle
|
||||||
editor,
|
.update(cx, |editor, cx| {
|
||||||
max_lines,
|
compute_auto_height_layout(
|
||||||
max_line_number_width,
|
editor,
|
||||||
known_dimensions,
|
max_lines,
|
||||||
cx,
|
max_line_number_width,
|
||||||
)
|
known_dimensions,
|
||||||
})
|
cx,
|
||||||
.unwrap_or_default()
|
)
|
||||||
})
|
})
|
||||||
}
|
.unwrap_or_default()
|
||||||
EditorMode::Full => {
|
},
|
||||||
let mut style = Style::default();
|
)
|
||||||
style.size.width = relative(1.).into();
|
}
|
||||||
style.size.height = relative(1.).into();
|
EditorMode::Full => {
|
||||||
cx.request_layout(&style, None)
|
let mut style = Style::default();
|
||||||
}
|
style.size.width = relative(1.).into();
|
||||||
};
|
style.size.height = relative(1.).into();
|
||||||
|
cx.request_layout(&style, None)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
(layout_id, ())
|
(layout_id, ())
|
||||||
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2850,65 +2855,67 @@ impl Element for EditorElement {
|
||||||
) {
|
) {
|
||||||
let editor = self.editor.clone();
|
let editor = self.editor.clone();
|
||||||
|
|
||||||
cx.with_text_style(
|
cx.paint_view(self.editor.entity_id(), |cx| {
|
||||||
Some(gpui::TextStyleRefinement {
|
cx.with_text_style(
|
||||||
font_size: Some(self.style.text.font_size),
|
Some(gpui::TextStyleRefinement {
|
||||||
..Default::default()
|
font_size: Some(self.style.text.font_size),
|
||||||
}),
|
..Default::default()
|
||||||
|cx| {
|
}),
|
||||||
let mut layout = self.compute_layout(bounds, cx);
|
|cx| {
|
||||||
let gutter_bounds = Bounds {
|
let mut layout = self.compute_layout(bounds, cx);
|
||||||
origin: bounds.origin,
|
let gutter_bounds = Bounds {
|
||||||
size: layout.gutter_size,
|
origin: bounds.origin,
|
||||||
};
|
size: layout.gutter_size,
|
||||||
let text_bounds = Bounds {
|
};
|
||||||
origin: gutter_bounds.upper_right(),
|
let text_bounds = Bounds {
|
||||||
size: layout.text_size,
|
origin: gutter_bounds.upper_right(),
|
||||||
};
|
size: layout.text_size,
|
||||||
|
};
|
||||||
|
|
||||||
let focus_handle = editor.focus_handle(cx);
|
let focus_handle = editor.focus_handle(cx);
|
||||||
let key_context = self.editor.read(cx).key_context(cx);
|
let key_context = self.editor.read(cx).key_context(cx);
|
||||||
cx.with_key_dispatch(Some(key_context), Some(focus_handle.clone()), |_, cx| {
|
cx.with_key_dispatch(Some(key_context), Some(focus_handle.clone()), |_, cx| {
|
||||||
self.register_actions(cx);
|
self.register_actions(cx);
|
||||||
self.register_key_listeners(cx);
|
self.register_key_listeners(cx);
|
||||||
|
|
||||||
cx.with_content_mask(Some(ContentMask { bounds }), |cx| {
|
cx.with_content_mask(Some(ContentMask { bounds }), |cx| {
|
||||||
let input_handler =
|
let input_handler =
|
||||||
ElementInputHandler::new(bounds, self.editor.clone(), cx);
|
ElementInputHandler::new(bounds, self.editor.clone(), cx);
|
||||||
cx.handle_input(&focus_handle, input_handler);
|
cx.handle_input(&focus_handle, input_handler);
|
||||||
|
|
||||||
self.paint_background(gutter_bounds, text_bounds, &layout, cx);
|
self.paint_background(gutter_bounds, text_bounds, &layout, cx);
|
||||||
if layout.gutter_size.width > Pixels::ZERO {
|
if layout.gutter_size.width > Pixels::ZERO {
|
||||||
self.paint_gutter(gutter_bounds, &mut layout, cx);
|
self.paint_gutter(gutter_bounds, &mut layout, cx);
|
||||||
}
|
}
|
||||||
self.paint_text(text_bounds, &mut layout, cx);
|
self.paint_text(text_bounds, &mut layout, cx);
|
||||||
|
|
||||||
cx.with_z_index(0, |cx| {
|
|
||||||
self.paint_mouse_listeners(
|
|
||||||
bounds,
|
|
||||||
gutter_bounds,
|
|
||||||
text_bounds,
|
|
||||||
&layout,
|
|
||||||
cx,
|
|
||||||
);
|
|
||||||
});
|
|
||||||
if !layout.blocks.is_empty() {
|
|
||||||
cx.with_z_index(0, |cx| {
|
cx.with_z_index(0, |cx| {
|
||||||
cx.with_element_id(Some("editor_blocks"), |cx| {
|
self.paint_mouse_listeners(
|
||||||
self.paint_blocks(bounds, &mut layout, cx);
|
bounds,
|
||||||
});
|
gutter_bounds,
|
||||||
})
|
text_bounds,
|
||||||
}
|
&layout,
|
||||||
|
cx,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
if !layout.blocks.is_empty() {
|
||||||
|
cx.with_z_index(0, |cx| {
|
||||||
|
cx.with_element_id(Some("editor_blocks"), |cx| {
|
||||||
|
self.paint_blocks(bounds, &mut layout, cx);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
cx.with_z_index(1, |cx| {
|
cx.with_z_index(1, |cx| {
|
||||||
self.paint_overlays(text_bounds, &mut layout, cx);
|
self.paint_overlays(text_bounds, &mut layout, cx);
|
||||||
|
});
|
||||||
|
|
||||||
|
cx.with_z_index(2, |cx| self.paint_scrollbar(bounds, &mut layout, cx));
|
||||||
});
|
});
|
||||||
|
})
|
||||||
cx.with_z_index(2, |cx| self.paint_scrollbar(bounds, &mut layout, cx));
|
},
|
||||||
});
|
)
|
||||||
})
|
})
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3588,10 +3595,8 @@ mod tests {
|
||||||
|
|
||||||
// Don't panic.
|
// Don't panic.
|
||||||
let bounds = Bounds::<Pixels>::new(Default::default(), size);
|
let bounds = Bounds::<Pixels>::new(Default::default(), size);
|
||||||
cx.update_window(window.into(), |view, cx| {
|
cx.update_window(window.into(), |view, cx| element.paint(bounds, &mut (), cx))
|
||||||
cx.paint_view(view.entity_id(), |cx| element.paint(bounds, &mut (), cx))
|
.unwrap()
|
||||||
})
|
|
||||||
.unwrap()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[gpui::test]
|
#[gpui::test]
|
||||||
|
|
|
@ -2009,24 +2009,34 @@ impl<'a> WindowContext<'a> {
|
||||||
pub fn with_view_id<R>(&mut self, view_id: EntityId, f: impl FnOnce(&mut Self) -> R) -> R {
|
pub fn with_view_id<R>(&mut self, view_id: EntityId, f: impl FnOnce(&mut Self) -> R) -> R {
|
||||||
let text_system = self.text_system().clone();
|
let text_system = self.text_system().clone();
|
||||||
text_system.with_view(view_id, || {
|
text_system.with_view(view_id, || {
|
||||||
self.window.next_frame.view_stack.push(view_id);
|
if self.window.next_frame.view_stack.last() == Some(&view_id) {
|
||||||
let result = f(self);
|
return f(self);
|
||||||
self.window.next_frame.view_stack.pop();
|
} else {
|
||||||
result
|
self.window.next_frame.view_stack.push(view_id);
|
||||||
|
let result = f(self);
|
||||||
|
self.window.next_frame.view_stack.pop();
|
||||||
|
result
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Invoke the given function with the given view id present on the view stack.
|
/// Invoke the given function with the given view id present on the view stack.
|
||||||
/// This is a fairly low-level method used to paint views.
|
/// This is a fairly low-level method used to paint views.
|
||||||
pub fn paint_view<R>(&mut self, view_id: EntityId, f: impl FnOnce(&mut Self) -> R) -> R {
|
pub fn paint_view<R>(&mut self, view_id: EntityId, f: impl FnOnce(&mut Self) -> R) -> R {
|
||||||
self.with_view_id(view_id, |cx| {
|
let text_system = self.text_system().clone();
|
||||||
cx.window
|
text_system.with_view(view_id, || {
|
||||||
.next_frame
|
if self.window.next_frame.view_stack.last() == Some(&view_id) {
|
||||||
.dispatch_tree
|
return f(self);
|
||||||
.push_node(None, None, Some(view_id));
|
} else {
|
||||||
let result = f(cx);
|
self.window.next_frame.view_stack.push(view_id);
|
||||||
cx.window.next_frame.dispatch_tree.pop_node();
|
self.window
|
||||||
result
|
.next_frame
|
||||||
|
.dispatch_tree
|
||||||
|
.push_node(None, None, Some(view_id));
|
||||||
|
let result = f(self);
|
||||||
|
self.window.next_frame.view_stack.pop();
|
||||||
|
result
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue