Compare commits

...
Sign in to create a new pull request.

1 commit

Author SHA1 Message Date
Julia
da3031c2db Try constructing the current frame's opaque layers during a post-layout phase
Unfinished, non-functional
2024-02-13 12:13:03 -05:00
15 changed files with 613 additions and 293 deletions

View file

@ -773,11 +773,11 @@ impl CompletionsMenu {
cx, cx,
); );
return cx.spawn(move |this, mut cx| async move { cx.spawn(move |this, mut cx| async move {
if let Some(true) = resolve_task.await.log_err() { if let Some(true) = resolve_task.await.log_err() {
this.update(&mut cx, |_, cx| cx.notify()).ok(); this.update(&mut cx, |_, cx| cx.notify()).ok();
} }
}); })
} }
fn attempt_resolve_selected_completion_documentation( fn attempt_resolve_selected_completion_documentation(

View file

@ -374,7 +374,7 @@ impl EditorElement {
) { ) {
let mouse_position = cx.mouse_position(); let mouse_position = cx.mouse_position();
if !text_bounds.contains(&mouse_position) if !text_bounds.contains(&mouse_position)
|| !cx.was_top_layer(&mouse_position, stacking_order) || !cx.is_top_layer(&mouse_position, stacking_order)
{ {
return; return;
} }
@ -406,7 +406,7 @@ impl EditorElement {
} else if !text_bounds.contains(&event.position) { } else if !text_bounds.contains(&event.position) {
return; return;
} }
if !cx.was_top_layer(&event.position, stacking_order) { if !cx.is_top_layer(&event.position, stacking_order) {
return; return;
} }
@ -478,11 +478,11 @@ impl EditorElement {
editor.select(SelectPhase::End, cx); editor.select(SelectPhase::End, cx);
} }
if interactive_bounds.visibly_contains(&event.position, cx) if interactive_bounds.did_visibly_contains(&event.position, cx)
&& !pending_nonempty_selections && !pending_nonempty_selections
&& event.modifiers.command && event.modifiers.command
&& text_bounds.contains(&event.position) && text_bounds.contains(&event.position)
&& cx.was_top_layer(&event.position, stacking_order) && cx.is_top_layer(&event.position, stacking_order)
{ {
let point = position_map.point_for_position(text_bounds, event.position); let point = position_map.point_for_position(text_bounds, event.position);
editor.handle_click_hovered_link(point, event.modifiers, cx); editor.handle_click_hovered_link(point, event.modifiers, cx);
@ -550,7 +550,7 @@ impl EditorElement {
let modifiers = event.modifiers; let modifiers = event.modifiers;
let text_hovered = text_bounds.contains(&event.position); let text_hovered = text_bounds.contains(&event.position);
let gutter_hovered = gutter_bounds.contains(&event.position); let gutter_hovered = gutter_bounds.contains(&event.position);
let was_top = cx.was_top_layer(&event.position, stacking_order); let was_top = cx.is_top_layer(&event.position, stacking_order);
editor.set_gutter_hovered(gutter_hovered, cx); editor.set_gutter_hovered(gutter_hovered, cx);
@ -903,7 +903,7 @@ impl EditorElement {
bounds: text_bounds, bounds: text_bounds,
stacking_order: cx.stacking_order().clone(), stacking_order: cx.stacking_order().clone(),
}; };
if interactive_text_bounds.visibly_contains(&cx.mouse_position(), cx) { if interactive_text_bounds.did_visibly_contains(&cx.mouse_position(), cx) {
if self if self
.editor .editor
.read(cx) .read(cx)
@ -1242,7 +1242,7 @@ impl EditorElement {
popover_origin.x = popover_origin.x + x_out_of_bounds; popover_origin.x = popover_origin.x + x_out_of_bounds;
} }
if cx.was_top_layer(&popover_origin, cx.stacking_order()) { if cx.is_top_layer(&popover_origin, cx.stacking_order()) {
cx.break_content_mask(|cx| { cx.break_content_mask(|cx| {
hover_popover.draw(popover_origin, available_space, cx) hover_popover.draw(popover_origin, available_space, cx)
}); });
@ -1537,7 +1537,7 @@ impl EditorElement {
stacking_order: cx.stacking_order().clone(), stacking_order: cx.stacking_order().clone(),
}; };
let mut mouse_position = cx.mouse_position(); let mut mouse_position = cx.mouse_position();
if interactive_track_bounds.visibly_contains(&mouse_position, cx) { if interactive_track_bounds.did_visibly_contains(&mouse_position, cx) {
cx.set_cursor_style(CursorStyle::Arrow); cx.set_cursor_style(CursorStyle::Arrow);
} }
@ -1567,7 +1567,7 @@ impl EditorElement {
cx.stop_propagation(); cx.stop_propagation();
} else { } else {
editor.scroll_manager.set_is_dragging_scrollbar(false, cx); editor.scroll_manager.set_is_dragging_scrollbar(false, cx);
if interactive_track_bounds.visibly_contains(&event.position, cx) { if interactive_track_bounds.did_visibly_contains(&event.position, cx) {
editor.scroll_manager.show_scrollbar(cx); editor.scroll_manager.show_scrollbar(cx);
} }
} }
@ -2652,14 +2652,14 @@ impl EditorElement {
move |event: &ScrollWheelEvent, phase, cx| { move |event: &ScrollWheelEvent, phase, cx| {
if phase == DispatchPhase::Bubble if phase == DispatchPhase::Bubble
&& interactive_bounds.visibly_contains(&event.position, cx) && interactive_bounds.did_visibly_contains(&event.position, cx)
{ {
delta = delta.coalesce(event.delta); delta = delta.coalesce(event.delta);
editor.update(cx, |editor, cx| { editor.update(cx, |editor, cx| {
let position = event.position; let position = event.position;
let position_map: &PositionMap = &position_map; let position_map: &PositionMap = &position_map;
let bounds = &interactive_bounds; let bounds = &interactive_bounds;
if !bounds.visibly_contains(&position, cx) { if !bounds.did_visibly_contains(&position, cx) {
return; return;
} }
@ -2719,7 +2719,7 @@ impl EditorElement {
move |event: &MouseDownEvent, phase, cx| { move |event: &MouseDownEvent, phase, cx| {
if phase == DispatchPhase::Bubble if phase == DispatchPhase::Bubble
&& interactive_bounds.visibly_contains(&event.position, cx) && interactive_bounds.did_visibly_contains(&event.position, cx)
{ {
match event.button { match event.button {
MouseButton::Left => editor.update(cx, |editor, cx| { MouseButton::Left => editor.update(cx, |editor, cx| {
@ -2786,7 +2786,7 @@ impl EditorElement {
) )
} }
if interactive_bounds.visibly_contains(&event.position, cx) { if interactive_bounds.did_visibly_contains(&event.position, cx) {
Self::mouse_moved( Self::mouse_moved(
editor, editor,
event, event,
@ -3067,7 +3067,7 @@ impl Element for EditorElement {
) { ) {
let editor = self.editor.clone(); let editor = self.editor.clone();
cx.paint_view(self.editor.entity_id(), |cx| { cx.with_view(self.editor.entity_id(), |cx| {
cx.with_text_style( cx.with_text_style(
Some(gpui::TextStyleRefinement { Some(gpui::TextStyleRefinement {
font_size: Some(self.style.text.font_size), font_size: Some(self.style.text.font_size),

View file

@ -40,7 +40,7 @@ use crate::{
}; };
use derive_more::{Deref, DerefMut}; use derive_more::{Deref, DerefMut};
pub(crate) use smallvec::SmallVec; pub(crate) use smallvec::SmallVec;
use std::{any::Any, fmt::Debug, ops::DerefMut}; use std::{any::{type_name_of_val, Any}, fmt::Debug, ops::DerefMut};
/// Implemented by types that participate in laying out and painting the contents of a window. /// Implemented by types that participate in laying out and painting the contents of a window.
/// Elements form a tree and are laid out according to web-based layout rules, as implemented by Taffy. /// Elements form a tree and are laid out according to web-based layout rules, as implemented by Taffy.
@ -59,6 +59,19 @@ pub trait Element: 'static + IntoElement {
cx: &mut ElementContext, cx: &mut ElementContext,
) -> (LayoutId, Self::State); ) -> (LayoutId, Self::State);
/// After layout is performed, we assign each element its bounds. Some elements may
/// need to use these bounds to render and layout the appropriate children. This is
/// also each element's opportunity to add opaque layers before painting [`crate::window::element_cx::add_opaque_layer`].
fn post_layout(
&mut self,
_bounds: Bounds<Pixels>,
_state: &mut Self::State,
_cx: &mut ElementContext,
) {
dbg!(type_name_of_val(self));
// TODO: Delete this default implementation once we've implemented it everywhere.
}
/// Once layout has been completed, this method will be called to paint the element to the screen. /// Once layout has been completed, this method will be called to paint the element to the screen.
/// The state argument is the same state that was returned from [`Element::request_layout()`]. /// The state argument is the same state that was returned from [`Element::request_layout()`].
fn paint(&mut self, bounds: Bounds<Pixels>, state: &mut Self::State, cx: &mut ElementContext); fn paint(&mut self, bounds: Bounds<Pixels>, state: &mut Self::State, cx: &mut ElementContext);
@ -229,6 +242,8 @@ trait ElementObject {
fn request_layout(&mut self, cx: &mut ElementContext) -> LayoutId; fn request_layout(&mut self, cx: &mut ElementContext) -> LayoutId;
fn post_layout(&mut self, cx: &mut ElementContext);
fn paint(&mut self, cx: &mut ElementContext); fn paint(&mut self, cx: &mut ElementContext);
fn measure( fn measure(
@ -301,6 +316,44 @@ impl<E: Element> DrawableElement<E> {
layout_id layout_id
} }
fn post_layout(&mut self, cx: &mut ElementContext) {
println!("DrawableElement post_layout");
match &mut self.phase {
ElementDrawPhase::LayoutRequested {
layout_id,
frame_state,
..
}
| ElementDrawPhase::LayoutComputed {
layout_id,
frame_state,
..
} => {
let bounds = cx.layout_bounds(*layout_id);
let element = self.element.as_mut().unwrap();
if let Some(frame_state) = frame_state.as_mut() {
println!("Some");
element.post_layout(bounds, frame_state, cx);
} else {
println!("Else");
let element_id = element
.element_id()
.expect("if we don't have frame state, we should have element state");
cx.with_element_state(element_id, |element_state, cx| {
println!("with_element_state");
let mut element_state = element_state.unwrap();
element.post_layout(bounds, &mut element_state, cx);
((), element_state)
});
}
}
_ => panic!("must call layout before post_layout"),
}
}
fn paint(mut self, cx: &mut ElementContext) -> Option<E::State> { fn paint(mut self, cx: &mut ElementContext) -> Option<E::State> {
match self.phase { match self.phase {
ElementDrawPhase::LayoutRequested { ElementDrawPhase::LayoutRequested {
@ -407,6 +460,11 @@ where
DrawableElement::request_layout(self.as_mut().unwrap(), cx) DrawableElement::request_layout(self.as_mut().unwrap(), cx)
} }
fn post_layout(&mut self, cx: &mut ElementContext) {
println!("ElementObject post_layout");
DrawableElement::post_layout(self.as_mut().unwrap(), cx)
}
fn paint(&mut self, cx: &mut ElementContext) { fn paint(&mut self, cx: &mut ElementContext) {
DrawableElement::paint(self.take().unwrap(), cx); DrawableElement::paint(self.take().unwrap(), cx);
} }
@ -450,6 +508,12 @@ impl AnyElement {
self.0.request_layout(cx) self.0.request_layout(cx)
} }
/// TODO
pub fn post_layout(&mut self, cx: &mut ElementContext) {
println!("AnyElement post_layout");
self.0.post_layout(cx)
}
/// Paints the element stored in this `AnyElement`. /// Paints the element stored in this `AnyElement`.
pub fn paint(&mut self, cx: &mut ElementContext) { pub fn paint(&mut self, cx: &mut ElementContext) {
self.0.paint(cx) self.0.paint(cx)
@ -491,6 +555,16 @@ impl Element for AnyElement {
let layout_id = self.request_layout(cx); let layout_id = self.request_layout(cx);
(layout_id, ()) (layout_id, ())
} }
fn post_layout(
&mut self,
_bounds: Bounds<Pixels>,
_state: &mut Self::State,
cx: &mut ElementContext,
) {
self.0.post_layout(cx);
}
fn paint(&mut self, _: Bounds<Pixels>, _: &mut Self::State, cx: &mut ElementContext) { fn paint(&mut self, _: Bounds<Pixels>, _: &mut Self::State, cx: &mut ElementContext) {
self.paint(cx) self.paint(cx)

View file

@ -88,7 +88,7 @@ impl Interactivity {
.push(Box::new(move |event, bounds, phase, cx| { .push(Box::new(move |event, bounds, phase, cx| {
if phase == DispatchPhase::Bubble if phase == DispatchPhase::Bubble
&& event.button == button && event.button == button
&& bounds.visibly_contains(&event.position, cx) && bounds.did_visibly_contains(&event.position, cx)
{ {
(listener)(event, cx) (listener)(event, cx)
} }
@ -105,7 +105,9 @@ impl Interactivity {
) { ) {
self.mouse_down_listeners self.mouse_down_listeners
.push(Box::new(move |event, bounds, phase, cx| { .push(Box::new(move |event, bounds, phase, cx| {
if phase == DispatchPhase::Capture && bounds.visibly_contains(&event.position, cx) { if phase == DispatchPhase::Capture
&& bounds.did_visibly_contains(&event.position, cx)
{
(listener)(event, cx) (listener)(event, cx)
} }
})); }));
@ -121,7 +123,9 @@ impl Interactivity {
) { ) {
self.mouse_down_listeners self.mouse_down_listeners
.push(Box::new(move |event, bounds, phase, cx| { .push(Box::new(move |event, bounds, phase, cx| {
if phase == DispatchPhase::Bubble && bounds.visibly_contains(&event.position, cx) { if phase == DispatchPhase::Bubble
&& bounds.did_visibly_contains(&event.position, cx)
{
(listener)(event, cx) (listener)(event, cx)
} }
})); }));
@ -140,7 +144,7 @@ impl Interactivity {
.push(Box::new(move |event, bounds, phase, cx| { .push(Box::new(move |event, bounds, phase, cx| {
if phase == DispatchPhase::Bubble if phase == DispatchPhase::Bubble
&& event.button == button && event.button == button
&& bounds.visibly_contains(&event.position, cx) && bounds.did_visibly_contains(&event.position, cx)
{ {
(listener)(event, cx) (listener)(event, cx)
} }
@ -157,7 +161,9 @@ impl Interactivity {
) { ) {
self.mouse_up_listeners self.mouse_up_listeners
.push(Box::new(move |event, bounds, phase, cx| { .push(Box::new(move |event, bounds, phase, cx| {
if phase == DispatchPhase::Capture && bounds.visibly_contains(&event.position, cx) { if phase == DispatchPhase::Capture
&& bounds.did_visibly_contains(&event.position, cx)
{
(listener)(event, cx) (listener)(event, cx)
} }
})); }));
@ -173,7 +179,9 @@ impl Interactivity {
) { ) {
self.mouse_up_listeners self.mouse_up_listeners
.push(Box::new(move |event, bounds, phase, cx| { .push(Box::new(move |event, bounds, phase, cx| {
if phase == DispatchPhase::Bubble && bounds.visibly_contains(&event.position, cx) { if phase == DispatchPhase::Bubble
&& bounds.did_visibly_contains(&event.position, cx)
{
(listener)(event, cx) (listener)(event, cx)
} }
})); }));
@ -190,7 +198,8 @@ impl Interactivity {
) { ) {
self.mouse_down_listeners self.mouse_down_listeners
.push(Box::new(move |event, bounds, phase, cx| { .push(Box::new(move |event, bounds, phase, cx| {
if phase == DispatchPhase::Capture && !bounds.visibly_contains(&event.position, cx) if phase == DispatchPhase::Capture
&& !bounds.did_visibly_contains(&event.position, cx)
{ {
(listener)(event, cx) (listener)(event, cx)
} }
@ -211,7 +220,7 @@ impl Interactivity {
.push(Box::new(move |event, bounds, phase, cx| { .push(Box::new(move |event, bounds, phase, cx| {
if phase == DispatchPhase::Capture if phase == DispatchPhase::Capture
&& event.button == button && event.button == button
&& !bounds.visibly_contains(&event.position, cx) && !bounds.did_visibly_contains(&event.position, cx)
{ {
(listener)(event, cx); (listener)(event, cx);
} }
@ -228,7 +237,9 @@ impl Interactivity {
) { ) {
self.mouse_move_listeners self.mouse_move_listeners
.push(Box::new(move |event, bounds, phase, cx| { .push(Box::new(move |event, bounds, phase, cx| {
if phase == DispatchPhase::Bubble && bounds.visibly_contains(&event.position, cx) { if phase == DispatchPhase::Bubble
&& bounds.did_visibly_contains(&event.position, cx)
{
(listener)(event, cx); (listener)(event, cx);
} }
})); }));
@ -277,7 +288,9 @@ impl Interactivity {
) { ) {
self.scroll_wheel_listeners self.scroll_wheel_listeners
.push(Box::new(move |event, bounds, phase, cx| { .push(Box::new(move |event, bounds, phase, cx| {
if phase == DispatchPhase::Bubble && bounds.visibly_contains(&event.position, cx) { if phase == DispatchPhase::Bubble
&& bounds.did_visibly_contains(&event.position, cx)
{
(listener)(event, cx); (listener)(event, cx);
} }
})); }));
@ -564,7 +577,7 @@ pub trait InteractiveElement: Sized {
self self
} }
#[cfg(any(test, feature = "test-support"))] // #[cfg(any(test, feature = "test-support"))]
/// Set a key that can be used to look up this element's bounds /// Set a key that can be used to look up this element's bounds
/// in the [`VisualTestContext::debug_bounds`] map /// in the [`VisualTestContext::debug_bounds`] map
/// This is a noop in release builds /// This is a noop in release builds
@ -573,14 +586,14 @@ pub trait InteractiveElement: Sized {
self self
} }
#[cfg(not(any(test, feature = "test-support")))] // #[cfg(not(any(test, feature = "test-support")))]
/// Set a key that can be used to look up this element's bounds // /// Set a key that can be used to look up this element's bounds
/// in the [`VisualTestContext::debug_bounds`] map // /// in the [`VisualTestContext::debug_bounds`] map
/// This is a noop in release builds // /// This is a noop in release builds
#[inline] // #[inline]
fn debug_selector(self, _: impl FnOnce() -> String) -> Self { // fn debug_selector(self, _: impl FnOnce() -> String) -> Self {
self // self
} // }
/// Bind the given callback to the mouse down event for any button, during the capture phase /// Bind the given callback to the mouse down event for any button, during the capture phase
/// the fluent API equivalent to [`Interactivity::capture_any_mouse_down`] /// the fluent API equivalent to [`Interactivity::capture_any_mouse_down`]
@ -1072,6 +1085,7 @@ impl Element for Div {
}) })
}, },
); );
( (
layout_id, layout_id,
DivState { DivState {
@ -1081,6 +1095,30 @@ impl Element for Div {
) )
} }
fn post_layout(
&mut self,
bounds: Bounds<Pixels>,
element_state: &mut Self::State,
cx: &mut ElementContext,
) {
dbg!(self.children.len());
self.interactivity.post_layout(
bounds,
&mut element_state.interactive_state,
cx,
|_, scroll_offset, cx| {
println!("in continuation");
cx.with_element_offset(scroll_offset, |cx| {
println!("in with_element_offset");
for child in &mut self.children {
println!("child");
child.post_layout(cx);
}
})
},
);
}
fn paint( fn paint(
&mut self, &mut self,
bounds: Bounds<Pixels>, bounds: Bounds<Pixels>,
@ -1207,7 +1245,7 @@ pub struct Interactivity {
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
pub(crate) location: Option<core::panic::Location<'static>>, pub(crate) location: Option<core::panic::Location<'static>>,
#[cfg(any(test, feature = "test-support"))] // #[cfg(any(test, feature = "test-support"))]
pub(crate) debug_selector: Option<String>, pub(crate) debug_selector: Option<String>,
} }
@ -1222,7 +1260,7 @@ pub struct InteractiveBounds {
impl InteractiveBounds { impl InteractiveBounds {
/// Checks whether this point was inside these bounds, and that these bounds where the topmost layer /// Checks whether this point was inside these bounds, and that these bounds where the topmost layer
pub fn visibly_contains(&self, point: &Point<Pixels>, cx: &WindowContext) -> bool { pub fn did_visibly_contains(&self, point: &Point<Pixels>, cx: &WindowContext) -> bool {
self.bounds.contains(point) && cx.was_top_layer(point, &self.stacking_order) self.bounds.contains(point) && cx.was_top_layer(point, &self.stacking_order)
} }
@ -1230,7 +1268,7 @@ impl InteractiveBounds {
/// under an active drag /// under an active drag
pub fn drag_target_contains(&self, point: &Point<Pixels>, cx: &WindowContext) -> bool { pub fn drag_target_contains(&self, point: &Point<Pixels>, cx: &WindowContext) -> bool {
self.bounds.contains(point) self.bounds.contains(point)
&& cx.was_top_layer_under_active_drag(point, &self.stacking_order) && cx.is_top_layer_under_active_drag(point, &self.stacking_order)
} }
} }
@ -1274,6 +1312,29 @@ impl Interactivity {
(layout_id, element_state) (layout_id, element_state)
} }
/// TODO
pub fn post_layout(
&mut self,
bounds: Bounds<Pixels>,
element_state: &mut InteractiveElementState,
cx: &mut ElementContext,
continuation: impl FnOnce(Bounds<Pixels>, Point<Pixels>, &mut ElementContext),
) {
let z_index = self.base_style.z_index.unwrap_or(0);
cx.with_z_index(z_index, |cx| {
println!("interactivity post_layout is adding an opaque layer");
cx.add_opaque_layer(bounds.intersect(&cx.content_mask().bounds));
let scroll_offset = element_state
.scroll_offset
.as_ref()
.map(|scroll_offset| *scroll_offset.borrow())
.unwrap_or_default();
continuation(bounds, scroll_offset, cx);
});
}
/// Paint this element according to this interactivity state's configured styles /// Paint this element according to this interactivity state's configured styles
/// and bind the element's mouse and keyboard events. /// and bind the element's mouse and keyboard events.
/// ///
@ -1288,11 +1349,8 @@ impl Interactivity {
content_size: Size<Pixels>, content_size: Size<Pixels>,
element_state: &mut InteractiveElementState, element_state: &mut InteractiveElementState,
cx: &mut ElementContext, cx: &mut ElementContext,
f: impl FnOnce(&Style, Point<Pixels>, &mut ElementContext), continuation: impl FnOnce(&Style, Point<Pixels>, &mut ElementContext),
) { ) {
let style = self.compute_style(Some(bounds), element_state, cx);
let z_index = style.z_index.unwrap_or(0);
#[cfg(any(feature = "test-support", test))] #[cfg(any(feature = "test-support", test))]
if let Some(debug_selector) = &self.debug_selector { if let Some(debug_selector) = &self.debug_selector {
cx.window cx.window
@ -1301,8 +1359,8 @@ impl Interactivity {
.insert(debug_selector.clone(), bounds); .insert(debug_selector.clone(), bounds);
} }
let paint_hover_group_handler = |cx: &mut ElementContext| { let paint_hover_group_handler = |this: &Self, cx: &mut ElementContext| {
let hover_group_bounds = self let hover_group_bounds = this
.group_hover_style .group_hover_style
.as_ref() .as_ref()
.and_then(|group_hover| GroupBounds::get(&group_hover.group, cx)); .and_then(|group_hover| GroupBounds::get(&group_hover.group, cx));
@ -1319,12 +1377,15 @@ impl Interactivity {
} }
}; };
if style.visibility == Visibility::Hidden { let z_index = self.base_style.z_index.unwrap_or(0);
cx.with_z_index(z_index, |cx| paint_hover_group_handler(cx));
return;
}
cx.with_z_index(z_index, |cx| { cx.with_z_index(z_index, |cx| {
let style = self.compute_style(Some(bounds), element_state, cx);
if style.visibility == Visibility::Hidden {
paint_hover_group_handler(self, cx);
return;
}
style.paint(bounds, cx, |cx: &mut ElementContext| { style.paint(bounds, cx, |cx: &mut ElementContext| {
cx.with_text_style(style.text_style().cloned(), |cx| { cx.with_text_style(style.text_style().cloned(), |cx| {
cx.with_content_mask(style.overflow_mask(bounds, cx.rem_size()), |cx| { cx.with_content_mask(style.overflow_mask(bounds, cx.rem_size()), |cx| {
@ -1439,19 +1500,19 @@ impl Interactivity {
stacking_order: cx.stacking_order().clone(), stacking_order: cx.stacking_order().clone(),
}; };
if self.block_mouse // if self.block_mouse
|| style.background.as_ref().is_some_and(|fill| { // || style.background.as_ref().is_some_and(|fill| {
fill.color().is_some_and(|color| !color.is_transparent()) // fill.color().is_some_and(|color| !color.is_transparent())
}) // })
{ // {
cx.add_opaque_layer(interactive_bounds.bounds); // cx.add_opaque_layer(interactive_bounds.bounds);
} // }
if !cx.has_active_drag() { if !cx.has_active_drag() {
if let Some(mouse_cursor) = style.mouse_cursor { if let Some(mouse_cursor) = style.mouse_cursor {
let mouse_position = &cx.mouse_position(); let mouse_position = &cx.mouse_position();
let hovered = let hovered =
interactive_bounds.visibly_contains(mouse_position, cx); interactive_bounds.did_visibly_contains(mouse_position, cx);
if hovered { if hovered {
cx.set_cursor_style(mouse_cursor); cx.set_cursor_style(mouse_cursor);
} }
@ -1467,7 +1528,8 @@ impl Interactivity {
move |event: &MouseDownEvent, phase, cx| { move |event: &MouseDownEvent, phase, cx| {
if phase == DispatchPhase::Bubble if phase == DispatchPhase::Bubble
&& !cx.default_prevented() && !cx.default_prevented()
&& interactive_bounds.visibly_contains(&event.position, cx) && interactive_bounds
.did_visibly_contains(&event.position, cx)
{ {
cx.focus(&focus_handle); cx.focus(&focus_handle);
// If there is a parent that is also focusable, prevent it // If there is a parent that is also focusable, prevent it
@ -1506,7 +1568,7 @@ impl Interactivity {
}) })
} }
paint_hover_group_handler(cx); paint_hover_group_handler(self, cx);
if self.hover_style.is_some() if self.hover_style.is_some()
|| self.base_style.mouse_cursor.is_some() || self.base_style.mouse_cursor.is_some()
@ -1585,7 +1647,8 @@ impl Interactivity {
move |event: &MouseDownEvent, phase, cx| { move |event: &MouseDownEvent, phase, cx| {
if phase == DispatchPhase::Bubble if phase == DispatchPhase::Bubble
&& event.button == MouseButton::Left && event.button == MouseButton::Left
&& interactive_bounds.visibly_contains(&event.position, cx) && interactive_bounds
.did_visibly_contains(&event.position, cx)
{ {
*pending_mouse_down.borrow_mut() = Some(event.clone()); *pending_mouse_down.borrow_mut() = Some(event.clone());
cx.refresh(); cx.refresh();
@ -1646,7 +1709,7 @@ impl Interactivity {
DispatchPhase::Bubble => { DispatchPhase::Bubble => {
if let Some(mouse_down) = captured_mouse_down.take() { if let Some(mouse_down) = captured_mouse_down.take() {
if interactive_bounds if interactive_bounds
.visibly_contains(&event.position, cx) .did_visibly_contains(&event.position, cx)
{ {
let mouse_click = ClickEvent { let mouse_click = ClickEvent {
down: mouse_down, down: mouse_down,
@ -1678,7 +1741,7 @@ impl Interactivity {
return; return;
} }
let is_hovered = interactive_bounds let is_hovered = interactive_bounds
.visibly_contains(&event.position, cx) .did_visibly_contains(&event.position, cx)
&& has_mouse_down.borrow().is_none() && has_mouse_down.borrow().is_none()
&& !cx.has_active_drag(); && !cx.has_active_drag();
let mut was_hovered = was_hovered.borrow_mut(); let mut was_hovered = was_hovered.borrow_mut();
@ -1705,7 +1768,7 @@ impl Interactivity {
cx.on_mouse_event(move |event: &MouseMoveEvent, phase, cx| { cx.on_mouse_event(move |event: &MouseMoveEvent, phase, cx| {
let is_hovered = interactive_bounds let is_hovered = interactive_bounds
.visibly_contains(&event.position, cx) .did_visibly_contains(&event.position, cx)
&& pending_mouse_down.borrow().is_none(); && pending_mouse_down.borrow().is_none();
if !is_hovered { if !is_hovered {
active_tooltip.borrow_mut().take(); active_tooltip.borrow_mut().take();
@ -1787,7 +1850,7 @@ impl Interactivity {
let group = active_group_bounds let group = active_group_bounds
.map_or(false, |bounds| bounds.contains(&down.position)); .map_or(false, |bounds| bounds.contains(&down.position));
let element = let element =
interactive_bounds.visibly_contains(&down.position, cx); interactive_bounds.did_visibly_contains(&down.position, cx);
if group || element { if group || element {
*active_state.borrow_mut() = *active_state.borrow_mut() =
ElementClickedState { group, element }; ElementClickedState { group, element };
@ -1840,7 +1903,7 @@ impl Interactivity {
let interactive_bounds = interactive_bounds.clone(); let interactive_bounds = interactive_bounds.clone();
cx.on_mouse_event(move |event: &ScrollWheelEvent, phase, cx| { cx.on_mouse_event(move |event: &ScrollWheelEvent, phase, cx| {
if phase == DispatchPhase::Bubble if phase == DispatchPhase::Bubble
&& interactive_bounds.visibly_contains(&event.position, cx) && interactive_bounds.did_visibly_contains(&event.position, cx)
{ {
let mut scroll_offset = scroll_offset.borrow_mut(); let mut scroll_offset = scroll_offset.borrow_mut();
let old_scroll_offset = *scroll_offset; let old_scroll_offset = *scroll_offset;
@ -1910,7 +1973,7 @@ impl Interactivity {
cx.on_action(action_type, listener) cx.on_action(action_type, listener)
} }
f(&style, scroll_offset.unwrap_or_default(), cx) continuation(&style, scroll_offset.unwrap_or_default(), cx)
}, },
); );
@ -1933,101 +1996,107 @@ impl Interactivity {
let mut style = Style::default(); let mut style = Style::default();
style.refine(&self.base_style); style.refine(&self.base_style);
cx.with_z_index(style.z_index.unwrap_or(0), |cx| { // cx.with_z_index(style.z_index.unwrap_or(0), |cx| {
if let Some(focus_handle) = self.tracked_focus_handle.as_ref() { if let Some(focus_handle) = self.tracked_focus_handle.as_ref() {
if let Some(in_focus_style) = self.in_focus_style.as_ref() { if let Some(in_focus_style) = self.in_focus_style.as_ref() {
if focus_handle.within_focused(cx) { if focus_handle.within_focused(cx) {
style.refine(in_focus_style); style.refine(in_focus_style);
}
}
if let Some(focus_style) = self.focus_style.as_ref() {
if focus_handle.is_focused(cx) {
style.refine(focus_style);
}
}
}
if let Some(bounds) = bounds {
let mouse_position = cx.mouse_position();
if !cx.has_active_drag() {
if let Some(group_hover) = self.group_hover_style.as_ref() {
if let Some(group_bounds) = GroupBounds::get(&group_hover.group, cx.deref_mut())
{
if group_bounds.contains(&mouse_position)
&& cx.is_top_layer(&mouse_position, cx.stacking_order())
{
style.refine(&group_hover.style);
}
} }
} }
if let Some(focus_style) = self.focus_style.as_ref() { if let Some(hover_style) = self.hover_style.as_ref() {
if focus_handle.is_focused(cx) { let outer_button = self.debug_selector.as_deref() == Some("outer_button");
style.refine(focus_style); let inner_button = self.debug_selector.as_deref() == Some("inner_button");
if outer_button {
cx.is_top_layer_debug(&mouse_position, cx.stacking_order());
}
println!("\n\n\n");
if bounds
.intersect(&cx.content_mask().bounds)
.contains(&mouse_position)
&& cx.is_top_layer(&mouse_position, cx.stacking_order())
{
style.refine(hover_style);
} }
} }
} }
if let Some(bounds) = bounds { if let Some(drag) = cx.active_drag.take() {
let mouse_position = cx.mouse_position(); let mut can_drop = true;
if !cx.has_active_drag() { if let Some(can_drop_predicate) = &self.can_drop_predicate {
if let Some(group_hover) = self.group_hover_style.as_ref() { can_drop = can_drop_predicate(drag.value.as_ref(), cx.deref_mut());
}
if can_drop {
for (state_type, group_drag_style) in &self.group_drag_over_styles {
if let Some(group_bounds) = if let Some(group_bounds) =
GroupBounds::get(&group_hover.group, cx.deref_mut()) GroupBounds::get(&group_drag_style.group, cx.deref_mut())
{ {
if group_bounds.contains(&mouse_position)
&& cx.was_top_layer(&mouse_position, cx.stacking_order())
{
style.refine(&group_hover.style);
}
}
}
if let Some(hover_style) = self.hover_style.as_ref() {
if bounds
.intersect(&cx.content_mask().bounds)
.contains(&mouse_position)
&& cx.was_top_layer(&mouse_position, cx.stacking_order())
{
style.refine(hover_style);
}
}
}
if let Some(drag) = cx.active_drag.take() {
let mut can_drop = true;
if let Some(can_drop_predicate) = &self.can_drop_predicate {
can_drop = can_drop_predicate(drag.value.as_ref(), cx.deref_mut());
}
if can_drop {
for (state_type, group_drag_style) in &self.group_drag_over_styles {
if let Some(group_bounds) =
GroupBounds::get(&group_drag_style.group, cx.deref_mut())
{
if *state_type == drag.value.as_ref().type_id()
&& group_bounds.contains(&mouse_position)
{
style.refine(&group_drag_style.style);
}
}
}
for (state_type, build_drag_over_style) in &self.drag_over_styles {
if *state_type == drag.value.as_ref().type_id() if *state_type == drag.value.as_ref().type_id()
&& bounds && group_bounds.contains(&mouse_position)
.intersect(&cx.content_mask().bounds)
.contains(&mouse_position)
&& cx.was_top_layer_under_active_drag(
&mouse_position,
cx.stacking_order(),
)
{ {
style.refine(&build_drag_over_style(drag.value.as_ref(), cx)); style.refine(&group_drag_style.style);
} }
} }
} }
cx.active_drag = Some(drag); for (state_type, build_drag_over_style) in &self.drag_over_styles {
if *state_type == drag.value.as_ref().type_id()
&& bounds
.intersect(&cx.content_mask().bounds)
.contains(&mouse_position)
&& cx.is_top_layer_under_active_drag(
&mouse_position,
cx.stacking_order(),
)
{
style.refine(&build_drag_over_style(drag.value.as_ref(), cx));
}
}
} }
}
let clicked_state = element_state cx.active_drag = Some(drag);
.clicked_state
.get_or_insert_with(Default::default)
.borrow();
if clicked_state.group {
if let Some(group) = self.group_active_style.as_ref() {
style.refine(&group.style)
}
} }
}
if let Some(active_style) = self.active_style.as_ref() { let clicked_state = element_state
if clicked_state.element { .clicked_state
style.refine(active_style) .get_or_insert_with(Default::default)
} .borrow();
if clicked_state.group {
if let Some(group) = self.group_active_style.as_ref() {
style.refine(&group.style)
} }
}); }
if let Some(active_style) = self.active_style.as_ref() {
if clicked_state.element {
style.refine(active_style)
}
}
// });
style style
} }
@ -2211,6 +2280,15 @@ where
self.element.request_layout(state, cx) self.element.request_layout(state, cx)
} }
fn post_layout(
&mut self,
bounds: Bounds<Pixels>,
state: &mut Self::State,
cx: &mut ElementContext,
) {
self.element.post_layout(bounds, state, cx);
}
fn paint(&mut self, bounds: Bounds<Pixels>, state: &mut Self::State, cx: &mut ElementContext) { fn paint(&mut self, bounds: Bounds<Pixels>, state: &mut Self::State, cx: &mut ElementContext) {
self.element.paint(bounds, state, cx) self.element.paint(bounds, state, cx)
} }

View file

@ -520,7 +520,7 @@ impl Element for List {
cx.on_mouse_event(move |event: &ScrollWheelEvent, phase, cx| { cx.on_mouse_event(move |event: &ScrollWheelEvent, phase, cx| {
if phase == DispatchPhase::Bubble if phase == DispatchPhase::Bubble
&& bounds.contains(&event.position) && bounds.contains(&event.position)
&& cx.was_top_layer(&event.position, cx.stacking_order()) && cx.is_top_layer(&event.position, cx.stacking_order())
{ {
list_state.0.borrow_mut().scroll( list_state.0.borrow_mut().scroll(
&scroll_top, &scroll_top,

View file

@ -427,7 +427,7 @@ impl Element for InteractiveText {
.clickable_ranges .clickable_ranges
.iter() .iter()
.any(|range| range.contains(&ix)) .any(|range| range.contains(&ix))
&& cx.was_top_layer(&mouse_position, cx.stacking_order()) && cx.is_top_layer(&mouse_position, cx.stacking_order())
{ {
cx.set_cursor_style(crate::CursorStyle::PointingHand) cx.set_cursor_style(crate::CursorStyle::PointingHand)
} }

View file

@ -105,7 +105,7 @@ impl<V: Render> Element for View<V> {
} }
fn paint(&mut self, _: Bounds<Pixels>, element: &mut Self::State, cx: &mut ElementContext) { fn paint(&mut self, _: Bounds<Pixels>, element: &mut Self::State, cx: &mut ElementContext) {
cx.paint_view(self.entity_id(), |cx| element.take().unwrap().paint(cx)); cx.with_view(self.entity_id(), |cx| element.take().unwrap().paint(cx));
} }
} }
@ -204,6 +204,7 @@ impl<V> Eq for WeakView<V> {}
pub struct AnyView { pub struct AnyView {
model: AnyModel, model: AnyModel,
request_layout: fn(&AnyView, &mut ElementContext) -> (LayoutId, AnyElement), request_layout: fn(&AnyView, &mut ElementContext) -> (LayoutId, AnyElement),
post_layout: fn(&mut AnyElement, &mut ElementContext),
cache: bool, cache: bool,
} }
@ -220,7 +221,8 @@ impl AnyView {
pub fn downgrade(&self) -> AnyWeakView { pub fn downgrade(&self) -> AnyWeakView {
AnyWeakView { AnyWeakView {
model: self.model.downgrade(), model: self.model.downgrade(),
layout: self.request_layout, request_layout: self.request_layout,
post_layout: self.post_layout,
} }
} }
@ -232,6 +234,7 @@ impl AnyView {
Err(model) => Err(Self { Err(model) => Err(Self {
model, model,
request_layout: self.request_layout, request_layout: self.request_layout,
post_layout: self.post_layout,
cache: self.cache, cache: self.cache,
}), }),
} }
@ -247,20 +250,34 @@ impl AnyView {
self.model.entity_id() self.model.entity_id()
} }
pub(crate) fn draw( pub(crate) fn layout_and_post_layout(
&self, &self,
origin: Point<Pixels>, origin: Point<Pixels>,
available_space: Size<AvailableSpace>, available_space: Size<AvailableSpace>,
cx: &mut ElementContext, cx: &mut ElementContext,
) { ) -> AnyElement {
cx.paint_view(self.entity_id(), |cx| { cx.with_view(self.entity_id(), |cx| {
cx.with_absolute_element_offset(origin, |cx| { cx.with_absolute_element_offset(origin, |cx| {
let (layout_id, mut rendered_element) = (self.request_layout)(self, cx); let (layout_id, mut rendered_element) = (self.request_layout)(self, cx);
cx.compute_layout(layout_id, available_space); cx.compute_layout(layout_id, available_space);
rendered_element.paint(cx) (self.post_layout)(&mut rendered_element, cx);
}); rendered_element
})
}) })
} }
pub(crate) fn paint(
&self,
origin: Point<Pixels>,
mut rendered_element: AnyElement,
cx: &mut ElementContext,
) {
cx.with_view(self.entity_id(), |cx| {
cx.with_absolute_element_offset(origin, |cx| {
rendered_element.paint(cx);
});
});
}
} }
impl<V: Render> From<View<V>> for AnyView { impl<V: Render> From<View<V>> for AnyView {
@ -268,6 +285,7 @@ impl<V: Render> From<View<V>> for AnyView {
AnyView { AnyView {
model: value.model.into_any(), model: value.model.into_any(),
request_layout: any_view::request_layout::<V>, request_layout: any_view::request_layout::<V>,
post_layout: any_view::post_layout,
cache: false, cache: false,
} }
} }
@ -300,9 +318,19 @@ impl Element for AnyView {
(layout_id, state) (layout_id, state)
}) })
} }
fn post_layout(
&mut self,
_bounds: Bounds<Pixels>,
state: &mut Self::State,
cx: &mut ElementContext,
) {
// todo!("move parts of caching")
state.element.as_mut().unwrap().post_layout(cx);
}
fn paint(&mut self, bounds: Bounds<Pixels>, state: &mut Self::State, cx: &mut ElementContext) { fn paint(&mut self, bounds: Bounds<Pixels>, state: &mut Self::State, cx: &mut ElementContext) {
cx.paint_view(self.entity_id(), |cx| { cx.with_view(self.entity_id(), |cx| {
if !self.cache { if !self.cache {
state.element.take().unwrap().paint(cx); state.element.take().unwrap().paint(cx);
return; return;
@ -328,13 +356,8 @@ impl Element for AnyView {
element.draw(bounds.origin, bounds.size.into(), cx); element.draw(bounds.origin, bounds.size.into(), cx);
} }
state.next_stacking_order_id = cx state.next_stacking_order_id =
.window cx.window.next_stacking_order_ids.last().copied().unwrap();
.next_frame
.next_stacking_order_ids
.last()
.copied()
.unwrap();
state.cache_key = Some(ViewCacheKey { state.cache_key = Some(ViewCacheKey {
bounds, bounds,
stacking_order: cx.stacking_order().clone(), stacking_order: cx.stacking_order().clone(),
@ -372,7 +395,8 @@ impl IntoElement for AnyView {
/// A weak, dynamically-typed view handle that does not prevent the view from being released. /// A weak, dynamically-typed view handle that does not prevent the view from being released.
pub struct AnyWeakView { pub struct AnyWeakView {
model: AnyWeakModel, model: AnyWeakModel,
layout: fn(&AnyView, &mut ElementContext) -> (LayoutId, AnyElement), request_layout: fn(&AnyView, &mut ElementContext) -> (LayoutId, AnyElement),
post_layout: fn(&mut AnyElement, &mut ElementContext),
} }
impl AnyWeakView { impl AnyWeakView {
@ -381,7 +405,8 @@ impl AnyWeakView {
let model = self.model.upgrade()?; let model = self.model.upgrade()?;
Some(AnyView { Some(AnyView {
model, model,
request_layout: self.layout, request_layout: self.request_layout,
post_layout: self.post_layout,
cache: false, cache: false,
}) })
} }
@ -391,7 +416,8 @@ impl<V: 'static + Render> From<WeakView<V>> for AnyWeakView {
fn from(view: WeakView<V>) -> Self { fn from(view: WeakView<V>) -> Self {
Self { Self {
model: view.model.into(), model: view.model.into(),
layout: any_view::request_layout::<V>, request_layout: any_view::request_layout::<V>,
post_layout: any_view::post_layout,
} }
} }
} }
@ -422,4 +448,8 @@ mod any_view {
let layout_id = element.request_layout(cx); let layout_id = element.request_layout(cx);
(layout_id, element) (layout_id, element)
} }
pub(crate) fn post_layout(element: &mut AnyElement, cx: &mut ElementContext) {
element.post_layout(cx);
}
} }

View file

@ -257,6 +257,9 @@ pub struct Window {
pub(crate) element_id_stack: GlobalElementId, pub(crate) element_id_stack: GlobalElementId,
pub(crate) rendered_frame: Frame, pub(crate) rendered_frame: Frame,
pub(crate) next_frame: Frame, pub(crate) next_frame: Frame,
pub(crate) z_index_stack: StackingOrder,
pub(crate) next_stacking_order_ids: Vec<u16>,
pub(crate) next_root_z_index: u16,
next_frame_callbacks: Rc<RefCell<Vec<FrameCallback>>>, next_frame_callbacks: Rc<RefCell<Vec<FrameCallback>>>,
pub(crate) dirty_views: FxHashSet<EntityId>, pub(crate) dirty_views: FxHashSet<EntityId>,
pub(crate) focus_handles: Arc<RwLock<SlotMap<FocusId, AtomicUsize>>>, pub(crate) focus_handles: Arc<RwLock<SlotMap<FocusId, AtomicUsize>>>,
@ -441,6 +444,9 @@ impl Window {
element_id_stack: GlobalElementId::default(), element_id_stack: GlobalElementId::default(),
rendered_frame: Frame::new(DispatchTree::new(cx.keymap.clone(), cx.actions.clone())), rendered_frame: Frame::new(DispatchTree::new(cx.keymap.clone(), cx.actions.clone())),
next_frame: Frame::new(DispatchTree::new(cx.keymap.clone(), cx.actions.clone())), next_frame: Frame::new(DispatchTree::new(cx.keymap.clone(), cx.actions.clone())),
z_index_stack: StackingOrder::default(),
next_stacking_order_ids: vec![0],
next_root_z_index: 0,
next_frame_callbacks, next_frame_callbacks,
dirty_views: FxHashSet::default(), dirty_views: FxHashSet::default(),
focus_handles: Arc::new(RwLock::new(SlotMap::with_key())), focus_handles: Arc::new(RwLock::new(SlotMap::with_key())),
@ -466,6 +472,7 @@ impl Window {
graphics_profiler_enabled: false, graphics_profiler_enabled: false,
} }
} }
fn new_focus_listener( fn new_focus_listener(
&mut self, &mut self,
value: AnyWindowFocusListener, value: AnyWindowFocusListener,
@ -848,6 +855,49 @@ impl<'a> WindowContext<'a> {
self.window.modifiers self.window.modifiers
} }
/// Returns true if there is no opaque layer containing the given point
/// on top of the given level. Layers who are extensions of the queried layer
/// are not considered to be on top of queried layer.
pub fn is_top_layer_debug(&self, point: &Point<Pixels>, layer: &StackingOrder) -> bool {
dbg!(point, layer);
dbg!(&self.window.next_frame.depth_map);
// Precondition: the depth map is ordered from topmost to bottomost.
for (opaque_layer, _, bounds) in self.window.next_frame.depth_map.iter() {
dbg!(opaque_layer);
if layer >= opaque_layer {
// The queried layer is either above or is the same as the this opaque layer.
// Anything after this point is guaranteed to be below the queried layer.
println!("is above or equal");
return true;
}
if !bounds.contains(point) {
// This opaque layer is above the queried layer but it doesn't contain
// the given position, so we can ignore it even if it's above.
println!("does not contain point");
continue;
}
// At this point, we've established that this opaque layer is on top of the queried layer
// and contains the position:
// If neither the opaque layer or the queried layer is an extension of the other then
// we know they are on different stacking orders, and return false.
// let is_on_same_layer = opaque_layer
// .iter()
// .zip(layer.iter())
// .all(|(a, b)| a.z_index == b.z_index);
// if !is_on_same_layer {
// return false;
// }
println!("returning false");
return false;
}
true
}
/// Returns true if there is no opaque layer containing the given point /// Returns true if there is no opaque layer containing the given point
/// on top of the given level. Layers who are extensions of the queried layer /// on top of the given level. Layers who are extensions of the queried layer
/// are not considered to be on top of queried layer. /// are not considered to be on top of queried layer.
@ -871,27 +921,65 @@ impl<'a> WindowContext<'a> {
// and contains the position: // and contains the position:
// If neither the opaque layer or the queried layer is an extension of the other then // If neither the opaque layer or the queried layer is an extension of the other then
// we know they are on different stacking orders, and return false. // we know they are on different stacking orders, and return false.
let is_on_same_layer = opaque_layer // let is_on_same_layer = opaque_layer
.iter() // .iter()
.zip(layer.iter()) // .zip(layer.iter())
.all(|(a, b)| a.z_index == b.z_index); // .all(|(a, b)| a.z_index == b.z_index);
if !is_on_same_layer { // if !is_on_same_layer {
return false; // return false;
} // }
return false;
} }
true true
} }
pub(crate) fn was_top_layer_under_active_drag( /// Returns true if there is no opaque layer containing the given point
/// on top of the given level. Layers who are extensions of the queried layer
/// are not considered to be on top of queried layer.
pub fn is_top_layer(&self, point: &Point<Pixels>, layer: &StackingOrder) -> bool {
// Precondition: the depth map is ordered from topmost to bottomost.
for (opaque_layer, _, bounds) in self.window.next_frame.depth_map.iter() {
if layer >= opaque_layer {
// The queried layer is either above or is the same as the this opaque layer.
// Anything after this point is guaranteed to be below the queried layer.
return true;
}
if !bounds.contains(point) {
// This opaque layer is above the queried layer but it doesn't contain
// the given position, so we can ignore it even if it's above.
continue;
}
// At this point, we've established that this opaque layer is on top of the queried layer
// and contains the position:
// If neither the opaque layer or the queried layer is an extension of the other then
// we know they are on different stacking orders, and return false.
// let is_on_same_layer = opaque_layer
// .iter()
// .zip(layer.iter())
// .all(|(a, b)| a.z_index == b.z_index);
// if !is_on_same_layer {
// return false;
// }
return false;
}
true
}
pub(crate) fn is_top_layer_under_active_drag(
&self, &self,
point: &Point<Pixels>, point: &Point<Pixels>,
layer: &StackingOrder, layer: &StackingOrder,
) -> bool { ) -> bool {
// Precondition: the depth map is ordered from topmost to bottomost. // Precondition: the depth map is ordered from topmost to bottomost.
for (opaque_layer, _, bounds) in self.window.rendered_frame.depth_map.iter() { for (opaque_layer, _, bounds) in self.window.next_frame.depth_map.iter() {
if layer >= opaque_layer { if layer >= opaque_layer {
// The queried layer is either above or is the same as the this opaque layer. // The queried layer is either above or is the same as the this opaque layer.
// Anything after this point is guaranteed to be below the queried layer. // Anything after this point is guaranteed to be below the queried layer.
@ -919,14 +1007,15 @@ impl<'a> WindowContext<'a> {
// and contains the position: // and contains the position:
// If neither the opaque layer or the queried layer is an extension of the other then // If neither the opaque layer or the queried layer is an extension of the other then
// we know they are on different stacking orders, and return false. // we know they are on different stacking orders, and return false.
let is_on_same_layer = opaque_layer // let is_on_same_layer = opaque_layer
.iter() // .iter()
.zip(layer.iter()) // .zip(layer.iter())
.all(|(a, b)| a.z_index == b.z_index); // .all(|(a, b)| a.z_index == b.z_index);
if !is_on_same_layer { // if !is_on_same_layer {
return false; // return false;
} // }
return false;
} }
true true
@ -934,7 +1023,7 @@ impl<'a> WindowContext<'a> {
/// Called during painting to get the current stacking order. /// Called during painting to get the current stacking order.
pub fn stacking_order(&self) -> &StackingOrder { pub fn stacking_order(&self) -> &StackingOrder {
&self.window.next_frame.z_index_stack &self.window.z_index_stack
} }
/// Produces a new frame and assigns it to `rendered_frame`. To actually show /// Produces a new frame and assigns it to `rendered_frame`. To actually show
@ -950,6 +1039,48 @@ impl<'a> WindowContext<'a> {
} }
let root_view = self.window.root_view.take().unwrap(); let root_view = self.window.root_view.take().unwrap();
let root_element = self.with_element_context(|cx| {
cx.with_z_index(0, |cx| {
let available_space = cx.window.viewport_size.map(Into::into);
root_view.layout_and_post_layout(Point::default(), available_space, cx)
})
});
let active_drag = self.app.active_drag.take();
let tooltip_request = self.window.next_frame.tooltip_request.take();
let drag_or_tooltip_element = if let Some(active_drag) = &active_drag {
self.with_element_context(|cx| {
cx.with_z_index(ACTIVE_DRAG_Z_INDEX, |cx| {
let offset = cx.mouse_position() - active_drag.cursor_offset;
let available_space =
size(AvailableSpace::MinContent, AvailableSpace::MinContent);
Some(
active_drag
.view
.layout_and_post_layout(offset, available_space, cx),
)
})
})
} else if let Some(tooltip_request) = &tooltip_request {
self.with_element_context(|cx| {
cx.with_z_index(1, |cx| {
let available_space =
size(AvailableSpace::MinContent, AvailableSpace::MinContent);
Some(tooltip_request.tooltip.view.layout_and_post_layout(
tooltip_request.tooltip.cursor_offset,
available_space,
cx,
))
})
})
} else {
None
};
assert_eq!(self.window.z_index_stack.len(), 0);
self.window.next_stacking_order_ids = vec![0];
self.with_element_context(|cx| { self.with_element_context(|cx| {
cx.with_z_index(0, |cx| { cx.with_z_index(0, |cx| {
cx.with_key_dispatch(Some(KeyContext::default()), None, |_, cx| { cx.with_key_dispatch(Some(KeyContext::default()), None, |_, cx| {
@ -967,36 +1098,35 @@ impl<'a> WindowContext<'a> {
} }
} }
let available_space = cx.window.viewport_size.map(Into::into); root_view.paint(Point::default(), root_element, cx);
root_view.draw(Point::default(), available_space, cx);
}) })
}) })
}); });
if let Some(active_drag) = self.app.active_drag.take() { if let Some(active_drag) = &active_drag {
self.with_element_context(|cx| { self.with_element_context(|cx| {
cx.with_z_index(ACTIVE_DRAG_Z_INDEX, |cx| { cx.with_z_index(ACTIVE_DRAG_Z_INDEX, |cx| {
let offset = cx.mouse_position() - active_drag.cursor_offset; let offset = cx.mouse_position() - active_drag.cursor_offset;
let available_space = active_drag
size(AvailableSpace::MinContent, AvailableSpace::MinContent); .view
active_drag.view.draw(offset, available_space, cx); .paint(offset, drag_or_tooltip_element.unwrap(), cx);
}) });
}); });
self.active_drag = Some(active_drag); } else if let Some(tooltip_request) = &tooltip_request {
} else if let Some(tooltip_request) = self.window.next_frame.tooltip_request.take() {
self.with_element_context(|cx| { self.with_element_context(|cx| {
cx.with_z_index(1, |cx| { cx.with_z_index(1, |cx| {
let available_space = tooltip_request.tooltip.view.paint(
size(AvailableSpace::MinContent, AvailableSpace::MinContent);
tooltip_request.tooltip.view.draw(
tooltip_request.tooltip.cursor_offset, tooltip_request.tooltip.cursor_offset,
available_space, drag_or_tooltip_element.unwrap(),
cx, cx,
); );
}) })
}); });
self.window.next_frame.tooltip_request = Some(tooltip_request);
} }
self.active_drag = active_drag;
self.window.next_frame.tooltip_request = tooltip_request;
self.window.dirty_views.clear(); self.window.dirty_views.clear();
self.window self.window
@ -1046,6 +1176,9 @@ impl<'a> WindowContext<'a> {
let previous_window_active = self.window.rendered_frame.window_active; let previous_window_active = self.window.rendered_frame.window_active;
mem::swap(&mut self.window.rendered_frame, &mut self.window.next_frame); mem::swap(&mut self.window.rendered_frame, &mut self.window.next_frame);
self.window.next_frame.clear(); self.window.next_frame.clear();
self.window.next_stacking_order_ids = vec![0];
self.window.next_root_z_index = 0;
self.window.z_index_stack.clear();
let current_focus_path = self.window.rendered_frame.focus_path(); let current_focus_path = self.window.rendered_frame.focus_path();
let current_window_active = self.window.rendered_frame.window_active; let current_window_active = self.window.rendered_frame.window_active;
@ -1078,6 +1211,8 @@ impl<'a> WindowContext<'a> {
} }
self.window.refreshing = false; self.window.refreshing = false;
self.window.drawing = false; self.window.drawing = false;
println!("\n\n\n\n");
} }
fn present(&self) { fn present(&self) {

View file

@ -59,9 +59,6 @@ pub(crate) struct Frame {
pub(crate) dispatch_tree: DispatchTree, pub(crate) dispatch_tree: DispatchTree,
pub(crate) scene: Scene, pub(crate) scene: Scene,
pub(crate) depth_map: Vec<(StackingOrder, EntityId, Bounds<Pixels>)>, pub(crate) depth_map: Vec<(StackingOrder, EntityId, Bounds<Pixels>)>,
pub(crate) z_index_stack: StackingOrder,
pub(crate) next_stacking_order_ids: Vec<u16>,
pub(crate) next_root_z_index: u16,
pub(crate) content_mask_stack: Vec<ContentMask<Pixels>>, pub(crate) content_mask_stack: Vec<ContentMask<Pixels>>,
pub(crate) element_offset_stack: Vec<Point<Pixels>>, pub(crate) element_offset_stack: Vec<Point<Pixels>>,
pub(crate) requested_input_handler: Option<RequestedInputHandler>, pub(crate) requested_input_handler: Option<RequestedInputHandler>,
@ -85,9 +82,6 @@ impl Frame {
dispatch_tree, dispatch_tree,
scene: Scene::default(), scene: Scene::default(),
depth_map: Vec::new(), depth_map: Vec::new(),
z_index_stack: StackingOrder::default(),
next_stacking_order_ids: vec![0],
next_root_z_index: 0,
content_mask_stack: Vec::new(), content_mask_stack: Vec::new(),
element_offset_stack: Vec::new(), element_offset_stack: Vec::new(),
requested_input_handler: None, requested_input_handler: None,
@ -107,8 +101,6 @@ impl Frame {
self.mouse_listeners.values_mut().for_each(Vec::clear); self.mouse_listeners.values_mut().for_each(Vec::clear);
self.dispatch_tree.clear(); self.dispatch_tree.clear();
self.depth_map.clear(); self.depth_map.clear();
self.next_stacking_order_ids = vec![0];
self.next_root_z_index = 0;
self.reused_views.clear(); self.reused_views.clear();
self.scene.clear(); self.scene.clear();
self.requested_input_handler.take(); self.requested_input_handler.take();
@ -318,6 +310,7 @@ impl<'a> ElementContext<'a> {
.next_frame .next_frame
.dispatch_tree .dispatch_tree
.reuse_view(view_id, &mut self.cx.window.rendered_frame.dispatch_tree); .reuse_view(view_id, &mut self.cx.window.rendered_frame.dispatch_tree);
for view_id in grafted_view_ids { for view_id in grafted_view_ids {
assert!(self.window.next_frame.reused_views.insert(view_id)); assert!(self.window.next_frame.reused_views.insert(view_id));
@ -353,21 +346,9 @@ impl<'a> ElementContext<'a> {
} }
debug_assert!( debug_assert!(
next_stacking_order_id next_stacking_order_id >= self.window.next_stacking_order_ids.last().copied().unwrap()
>= self
.window
.next_frame
.next_stacking_order_ids
.last()
.copied()
.unwrap()
); );
*self *self.window.next_stacking_order_ids.last_mut().unwrap() = next_stacking_order_id;
.window
.next_frame
.next_stacking_order_ids
.last_mut()
.unwrap() = next_stacking_order_id;
} }
/// Push a text style onto the stack, and call a function with that style active. /// Push a text style onto the stack, and call a function with that style active.
@ -440,6 +421,7 @@ impl<'a> ElementContext<'a> {
/// Invoke the given function with the content mask reset to that /// Invoke the given function with the content mask reset to that
/// of the window. /// of the window.
/// TODO: Don't call this during paint, that is very bad and broken
pub fn break_content_mask<R>(&mut self, f: impl FnOnce(&mut Self) -> R) -> R { pub fn break_content_mask<R>(&mut self, f: impl FnOnce(&mut Self) -> R) -> R {
let mask = ContentMask { let mask = ContentMask {
bounds: Bounds { bounds: Bounds {
@ -448,10 +430,9 @@ impl<'a> ElementContext<'a> {
}, },
}; };
let new_root_z_index = post_inc(&mut self.window_mut().next_frame.next_root_z_index); let new_root_z_index = post_inc(&mut self.window_mut().next_root_z_index);
let new_stacking_order_id = post_inc( let new_stacking_order_id = post_inc(
self.window_mut() self.window_mut()
.next_frame
.next_stacking_order_ids .next_stacking_order_ids
.last_mut() .last_mut()
.unwrap(), .unwrap(),
@ -461,13 +442,13 @@ impl<'a> ElementContext<'a> {
id: new_stacking_order_id, id: new_stacking_order_id,
}; };
let old_stacking_order = mem::take(&mut self.window_mut().next_frame.z_index_stack); let old_stacking_order = mem::take(&mut self.window_mut().z_index_stack);
self.window_mut().next_frame.z_index_stack.push(new_context); self.window_mut().z_index_stack.push(new_context);
self.window_mut().next_frame.content_mask_stack.push(mask); self.window_mut().next_frame.content_mask_stack.push(mask);
let result = f(self); let result = f(self);
self.window_mut().next_frame.content_mask_stack.pop(); self.window_mut().next_frame.content_mask_stack.pop();
self.window_mut().next_frame.z_index_stack = old_stacking_order; self.window_mut().z_index_stack = old_stacking_order;
result result
} }
@ -477,22 +458,29 @@ impl<'a> ElementContext<'a> {
pub fn with_z_index<R>(&mut self, z_index: u16, f: impl FnOnce(&mut Self) -> R) -> R { pub fn with_z_index<R>(&mut self, z_index: u16, f: impl FnOnce(&mut Self) -> R) -> R {
let new_stacking_order_id = post_inc( let new_stacking_order_id = post_inc(
self.window_mut() self.window_mut()
.next_frame
.next_stacking_order_ids .next_stacking_order_ids
.last_mut() .last_mut()
.unwrap(), .unwrap(),
); );
self.window_mut().next_frame.next_stacking_order_ids.push(0); self.window_mut().next_stacking_order_ids.push(0);
let new_context = StackingContext { let new_context = StackingContext {
z_index, z_index,
id: new_stacking_order_id, id: new_stacking_order_id,
}; };
self.window_mut().next_frame.z_index_stack.push(new_context); self.window_mut().z_index_stack.push(new_context);
let result = f(self);
self.window_mut().next_frame.z_index_stack.pop(); if self.window.z_index_stack.len() == 2 {
let last = self.window.z_index_stack.last().unwrap();
if last.z_index == 0 && last.id == 5 {
panic!();
}
}
self.window_mut().next_frame.next_stacking_order_ids.pop(); let result = f(self);
self.window_mut().z_index_stack.pop();
self.window_mut().next_stacking_order_ids.pop();
result result
} }
@ -667,7 +655,7 @@ impl<'a> ElementContext<'a> {
shadow_bounds.origin += shadow.offset; shadow_bounds.origin += shadow.offset;
shadow_bounds.dilate(shadow.spread_radius); shadow_bounds.dilate(shadow.spread_radius);
window.next_frame.scene.insert( window.next_frame.scene.insert(
&window.next_frame.z_index_stack, &window.z_index_stack,
Shadow { Shadow {
view_id: view_id.into(), view_id: view_id.into(),
layer_id: 0, layer_id: 0,
@ -693,7 +681,7 @@ impl<'a> ElementContext<'a> {
let window = &mut *self.window; let window = &mut *self.window;
window.next_frame.scene.insert( window.next_frame.scene.insert(
&window.next_frame.z_index_stack, &window.z_index_stack,
Quad { Quad {
view_id: view_id.into(), view_id: view_id.into(),
layer_id: 0, layer_id: 0,
@ -721,7 +709,7 @@ impl<'a> ElementContext<'a> {
window window
.next_frame .next_frame
.scene .scene
.insert(&window.next_frame.z_index_stack, path.scale(scale_factor)); .insert(&window.z_index_stack, path.scale(scale_factor));
} }
/// Paint an underline into the scene for the next frame at the current z-index. /// Paint an underline into the scene for the next frame at the current z-index.
@ -746,7 +734,7 @@ impl<'a> ElementContext<'a> {
let window = &mut *self.window; let window = &mut *self.window;
window.next_frame.scene.insert( window.next_frame.scene.insert(
&window.next_frame.z_index_stack, &window.z_index_stack,
Underline { Underline {
view_id: view_id.into(), view_id: view_id.into(),
layer_id: 0, layer_id: 0,
@ -778,7 +766,7 @@ impl<'a> ElementContext<'a> {
let window = &mut *self.window; let window = &mut *self.window;
window.next_frame.scene.insert( window.next_frame.scene.insert(
&window.next_frame.z_index_stack, &window.z_index_stack,
Underline { Underline {
view_id: view_id.into(), view_id: view_id.into(),
layer_id: 0, layer_id: 0,
@ -838,7 +826,7 @@ impl<'a> ElementContext<'a> {
let view_id = self.parent_view_id(); let view_id = self.parent_view_id();
let window = &mut *self.window; let window = &mut *self.window;
window.next_frame.scene.insert( window.next_frame.scene.insert(
&window.next_frame.z_index_stack, &window.z_index_stack,
MonochromeSprite { MonochromeSprite {
view_id: view_id.into(), view_id: view_id.into(),
layer_id: 0, layer_id: 0,
@ -896,7 +884,7 @@ impl<'a> ElementContext<'a> {
let window = &mut *self.window; let window = &mut *self.window;
window.next_frame.scene.insert( window.next_frame.scene.insert(
&window.next_frame.z_index_stack, &window.z_index_stack,
PolychromeSprite { PolychromeSprite {
view_id: view_id.into(), view_id: view_id.into(),
layer_id: 0, layer_id: 0,
@ -942,7 +930,7 @@ impl<'a> ElementContext<'a> {
let window = &mut *self.window; let window = &mut *self.window;
window.next_frame.scene.insert( window.next_frame.scene.insert(
&window.next_frame.z_index_stack, &window.z_index_stack,
MonochromeSprite { MonochromeSprite {
view_id: view_id.into(), view_id: view_id.into(),
layer_id: 0, layer_id: 0,
@ -981,7 +969,7 @@ impl<'a> ElementContext<'a> {
let window = &mut *self.window; let window = &mut *self.window;
window.next_frame.scene.insert( window.next_frame.scene.insert(
&window.next_frame.z_index_stack, &window.z_index_stack,
PolychromeSprite { PolychromeSprite {
view_id: view_id.into(), view_id: view_id.into(),
layer_id: 0, layer_id: 0,
@ -1006,7 +994,7 @@ impl<'a> ElementContext<'a> {
let view_id = self.parent_view_id(); let view_id = self.parent_view_id();
let window = &mut *self.window; let window = &mut *self.window;
window.next_frame.scene.insert( window.next_frame.scene.insert(
&window.next_frame.z_index_stack, &window.z_index_stack,
crate::Surface { crate::Surface {
view_id: view_id.into(), view_id: view_id.into(),
layer_id: 0, layer_id: 0,
@ -1092,9 +1080,10 @@ impl<'a> ElementContext<'a> {
.requested_style(layout_id) .requested_style(layout_id)
} }
/// Called during painting to track which z-index is on top at each pixel position /// TODO
pub fn add_opaque_layer(&mut self, bounds: Bounds<Pixels>) { pub fn add_opaque_layer(&mut self, bounds: Bounds<Pixels>) {
let stacking_order = self.window.next_frame.z_index_stack.clone(); assert_ne!(self.window.z_index_stack.last().cloned().unwrap().id, 6);
let stacking_order = self.window.z_index_stack.clone();
let view_id = self.parent_view_id(); let view_id = self.parent_view_id();
let depth_map = &mut self.window.next_frame.depth_map; let depth_map = &mut self.window.next_frame.depth_map;
match depth_map.binary_search_by(|(level, _, _)| stacking_order.cmp(level)) { match depth_map.binary_search_by(|(level, _, _)| stacking_order.cmp(level)) {
@ -1141,8 +1130,8 @@ impl<'a> ElementContext<'a> {
} }
/// 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 in the post-layout and paint phase of views.
pub fn paint_view<R>(&mut self, view_id: EntityId, f: impl FnOnce(&mut Self) -> R) -> R { pub fn with_view<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, || {
if self.window.next_frame.view_stack.last() == Some(&view_id) { if self.window.next_frame.view_stack.last() == Some(&view_id) {
@ -1188,7 +1177,7 @@ impl<'a> ElementContext<'a> {
mut handler: impl FnMut(&Event, DispatchPhase, &mut ElementContext) + 'static, mut handler: impl FnMut(&Event, DispatchPhase, &mut ElementContext) + 'static,
) { ) {
let view_id = self.parent_view_id(); let view_id = self.parent_view_id();
let order = self.window.next_frame.z_index_stack.clone(); let order = self.window.z_index_stack.clone();
self.window self.window
.next_frame .next_frame
.mouse_listeners .mouse_listeners

View file

@ -10,37 +10,49 @@ impl Render for ZIndexStory {
fn render(&mut self, _cx: &mut ViewContext<Self>) -> impl IntoElement { fn render(&mut self, _cx: &mut ViewContext<Self>) -> impl IntoElement {
Story::container().child(Story::title("z-index")).child( Story::container().child(Story::title("z-index")).child(
div() div()
.flex() .debug_selector(|| "outer_button".into())
.size_20()
.bg(gpui::red())
.hover(|s| s.bg(gpui::green()))
.child( .child(
div() div()
.w(px(250.)) .debug_selector(|| "inner_button".into())
.child(Story::label("z-index: auto")) .z_index(0)
.child(ZIndexExample::new(0)), .size_8()
) .bg(gpui::yellow())
.child( .hover(|s| s.bg(gpui::blue())),
div() ), // div()
.w(px(250.)) // .flex()
.child(Story::label("z-index: 1")) // .child(
.child(ZIndexExample::new(1)), // div()
) // .w(px(250.))
.child( // .child(Story::label("z-index: auto"))
div() // .child(ZIndexExample::new(0)),
.w(px(250.)) // )
.child(Story::label("z-index: 3")) // .child(
.child(ZIndexExample::new(3)), // div()
) // .w(px(250.))
.child( // .child(Story::label("z-index: 1"))
div() // .child(ZIndexExample::new(1)),
.w(px(250.)) // )
.child(Story::label("z-index: 5")) // .child(
.child(ZIndexExample::new(5)), // div()
) // .w(px(250.))
.child( // .child(Story::label("z-index: 3"))
div() // .child(ZIndexExample::new(3)),
.w(px(250.)) // )
.child(Story::label("z-index: 7")) // .child(
.child(ZIndexExample::new(7)), // div()
), // .w(px(250.))
// .child(Story::label("z-index: 5"))
// .child(ZIndexExample::new(5)),
// )
// .child(
// div()
// .w(px(250.))
// .child(Story::label("z-index: 7"))
// .child(ZIndexExample::new(7)),
// ),
) )
} }
} }

View file

@ -37,26 +37,27 @@ fn main() {
SimpleLogger::init(LevelFilter::Info, Default::default()).expect("could not initialize logger"); SimpleLogger::init(LevelFilter::Info, Default::default()).expect("could not initialize logger");
let args = Args::parse(); // let args = Args::parse();
let story_selector = args.story.clone().unwrap_or_else(|| { // let story_selector = args.story.clone().unwrap_or_else(|| {
let stories = ComponentStory::iter().collect::<Vec<_>>(); // let stories = ComponentStory::iter().collect::<Vec<_>>();
ctrlc::set_handler(move || {}).unwrap(); // ctrlc::set_handler(move || {}).unwrap();
let result = FuzzySelect::new() // let result = FuzzySelect::new()
.with_prompt("Choose a story to run:") // .with_prompt("Choose a story to run:")
.items(&stories) // .items(&stories)
.interact(); // .interact();
let Ok(selection) = result else { // let Ok(selection) = result else {
dialoguer::console::Term::stderr().show_cursor().unwrap(); // dialoguer::console::Term::stderr().show_cursor().unwrap();
std::process::exit(0); // std::process::exit(0);
}; // };
StorySelector::Component(stories[selection]) // StorySelector::Component(stories[selection])
}); // });
let theme_name = args.theme.unwrap_or("One Dark".to_string()); // let theme_name = args.theme.unwrap_or("One Dark".to_string());
let theme_name = "One Dark".to_string();
gpui::App::new().with_assets(Assets).run(move |cx| { gpui::App::new().with_assets(Assets).run(move |cx| {
load_embedded_fonts(cx).unwrap(); load_embedded_fonts(cx).unwrap();
@ -69,7 +70,7 @@ fn main() {
theme::init(theme::LoadThemes::All(Box::new(Assets)), cx); theme::init(theme::LoadThemes::All(Box::new(Assets)), cx);
let selector = story_selector; // let selector = story_selector;
let theme_registry = ThemeRegistry::global(cx); let theme_registry = ThemeRegistry::global(cx);
let mut theme_settings = ThemeSettings::get_global(cx).clone(); let mut theme_settings = ThemeSettings::get_global(cx).clone();
@ -91,7 +92,8 @@ fn main() {
let ui_font_size = ThemeSettings::get_global(cx).ui_font_size; let ui_font_size = ThemeSettings::get_global(cx).ui_font_size;
cx.set_rem_size(ui_font_size); cx.set_rem_size(ui_font_size);
cx.new_view(|cx| StoryWrapper::new(selector.story(cx))) // cx.new_view(|cx| StoryWrapper::new(selector.story(cx)))
cx.new_view(|cx| stories::ZIndexStory)
}, },
); );

View file

@ -493,7 +493,7 @@ impl TerminalElement {
bounds, bounds,
stacking_order: cx.stacking_order().clone(), stacking_order: cx.stacking_order().clone(),
}; };
if interactive_text_bounds.visibly_contains(&cx.mouse_position(), cx) { if interactive_text_bounds.did_visibly_contains(&cx.mouse_position(), cx) {
if self.can_navigate_to_selected_word && last_hovered_word.is_some() { if self.can_navigate_to_selected_word && last_hovered_word.is_some() {
cx.set_cursor_style(gpui::CursorStyle::PointingHand) cx.set_cursor_style(gpui::CursorStyle::PointingHand)
} else { } else {
@ -658,7 +658,7 @@ impl TerminalElement {
} }
if e.pressed_button.is_some() && !cx.has_active_drag() { if e.pressed_button.is_some() && !cx.has_active_drag() {
let visibly_contains = interactive_bounds.visibly_contains(&e.position, cx); let visibly_contains = interactive_bounds.did_visibly_contains(&e.position, cx);
terminal.update(cx, |terminal, cx| { terminal.update(cx, |terminal, cx| {
if !terminal.selection_started() { if !terminal.selection_started() {
if visibly_contains { if visibly_contains {
@ -672,7 +672,7 @@ impl TerminalElement {
}) })
} }
if interactive_bounds.visibly_contains(&e.position, cx) { if interactive_bounds.did_visibly_contains(&e.position, cx) {
terminal.update(cx, |terminal, cx| { terminal.update(cx, |terminal, cx| {
terminal.mouse_move(&e, origin); terminal.mouse_move(&e, origin);
cx.notify(); cx.notify();

View file

@ -212,7 +212,7 @@ impl<M: ManagedView> Element for PopoverMenu<M> {
// want a click on the toggle to re-open it. // want a click on the toggle to re-open it.
cx.on_mouse_event(move |e: &MouseDownEvent, phase, cx| { cx.on_mouse_event(move |e: &MouseDownEvent, phase, cx| {
if phase == DispatchPhase::Bubble if phase == DispatchPhase::Bubble
&& interactive_bounds.visibly_contains(&e.position, cx) && interactive_bounds.did_visibly_contains(&e.position, cx)
{ {
cx.stop_propagation() cx.stop_propagation()
} }

View file

@ -143,7 +143,7 @@ impl<M: ManagedView> Element for RightClickMenu<M> {
cx.on_mouse_event(move |event: &MouseDownEvent, phase, cx| { cx.on_mouse_event(move |event: &MouseDownEvent, phase, cx| {
if phase == DispatchPhase::Bubble if phase == DispatchPhase::Bubble
&& event.button == MouseButton::Right && event.button == MouseButton::Right
&& interactive_bounds.visibly_contains(&event.position, cx) && interactive_bounds.did_visibly_contains(&event.position, cx)
{ {
cx.stop_propagation(); cx.stop_propagation();
cx.prevent_default(); cx.prevent_default();

View file

@ -758,7 +758,7 @@ mod element {
bounds: handle_bounds, bounds: handle_bounds,
stacking_order: cx.stacking_order().clone(), stacking_order: cx.stacking_order().clone(),
}; };
if interactive_handle_bounds.visibly_contains(&cx.mouse_position(), cx) { if interactive_handle_bounds.did_visibly_contains(&cx.mouse_position(), cx) {
cx.set_cursor_style(match axis { cx.set_cursor_style(match axis {
Axis::Vertical => CursorStyle::ResizeUpDown, Axis::Vertical => CursorStyle::ResizeUpDown,
Axis::Horizontal => CursorStyle::ResizeLeftRight, Axis::Horizontal => CursorStyle::ResizeLeftRight,