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,
);
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() {
this.update(&mut cx, |_, cx| cx.notify()).ok();
}
});
})
}
fn attempt_resolve_selected_completion_documentation(

View file

@ -374,7 +374,7 @@ impl EditorElement {
) {
let mouse_position = cx.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;
}
@ -406,7 +406,7 @@ impl EditorElement {
} else if !text_bounds.contains(&event.position) {
return;
}
if !cx.was_top_layer(&event.position, stacking_order) {
if !cx.is_top_layer(&event.position, stacking_order) {
return;
}
@ -478,11 +478,11 @@ impl EditorElement {
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
&& event.modifiers.command
&& 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);
editor.handle_click_hovered_link(point, event.modifiers, cx);
@ -550,7 +550,7 @@ impl EditorElement {
let modifiers = event.modifiers;
let text_hovered = text_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);
@ -903,7 +903,7 @@ impl EditorElement {
bounds: text_bounds,
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
.editor
.read(cx)
@ -1242,7 +1242,7 @@ impl EditorElement {
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| {
hover_popover.draw(popover_origin, available_space, cx)
});
@ -1537,7 +1537,7 @@ impl EditorElement {
stacking_order: cx.stacking_order().clone(),
};
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);
}
@ -1567,7 +1567,7 @@ impl EditorElement {
cx.stop_propagation();
} else {
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);
}
}
@ -2652,14 +2652,14 @@ impl EditorElement {
move |event: &ScrollWheelEvent, phase, cx| {
if phase == DispatchPhase::Bubble
&& interactive_bounds.visibly_contains(&event.position, cx)
&& interactive_bounds.did_visibly_contains(&event.position, cx)
{
delta = delta.coalesce(event.delta);
editor.update(cx, |editor, cx| {
let position = event.position;
let position_map: &PositionMap = &position_map;
let bounds = &interactive_bounds;
if !bounds.visibly_contains(&position, cx) {
if !bounds.did_visibly_contains(&position, cx) {
return;
}
@ -2719,7 +2719,7 @@ impl EditorElement {
move |event: &MouseDownEvent, phase, cx| {
if phase == DispatchPhase::Bubble
&& interactive_bounds.visibly_contains(&event.position, cx)
&& interactive_bounds.did_visibly_contains(&event.position, cx)
{
match event.button {
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(
editor,
event,
@ -3067,7 +3067,7 @@ impl Element for EditorElement {
) {
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(
Some(gpui::TextStyleRefinement {
font_size: Some(self.style.text.font_size),

View file

@ -40,7 +40,7 @@ use crate::{
};
use derive_more::{Deref, DerefMut};
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.
/// 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,
) -> (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.
/// 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);
@ -229,6 +242,8 @@ trait ElementObject {
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 measure(
@ -301,6 +316,44 @@ impl<E: Element> DrawableElement<E> {
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> {
match self.phase {
ElementDrawPhase::LayoutRequested {
@ -407,6 +460,11 @@ where
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) {
DrawableElement::paint(self.take().unwrap(), cx);
}
@ -450,6 +508,12 @@ impl AnyElement {
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`.
pub fn paint(&mut self, cx: &mut ElementContext) {
self.0.paint(cx)
@ -491,6 +555,16 @@ impl Element for AnyElement {
let layout_id = self.request_layout(cx);
(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) {
self.paint(cx)

View file

@ -88,7 +88,7 @@ impl Interactivity {
.push(Box::new(move |event, bounds, phase, cx| {
if phase == DispatchPhase::Bubble
&& event.button == button
&& bounds.visibly_contains(&event.position, cx)
&& bounds.did_visibly_contains(&event.position, cx)
{
(listener)(event, cx)
}
@ -105,7 +105,9 @@ impl Interactivity {
) {
self.mouse_down_listeners
.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)
}
}));
@ -121,7 +123,9 @@ impl Interactivity {
) {
self.mouse_down_listeners
.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)
}
}));
@ -140,7 +144,7 @@ impl Interactivity {
.push(Box::new(move |event, bounds, phase, cx| {
if phase == DispatchPhase::Bubble
&& event.button == button
&& bounds.visibly_contains(&event.position, cx)
&& bounds.did_visibly_contains(&event.position, cx)
{
(listener)(event, cx)
}
@ -157,7 +161,9 @@ impl Interactivity {
) {
self.mouse_up_listeners
.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)
}
}));
@ -173,7 +179,9 @@ impl Interactivity {
) {
self.mouse_up_listeners
.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)
}
}));
@ -190,7 +198,8 @@ impl Interactivity {
) {
self.mouse_down_listeners
.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)
}
@ -211,7 +220,7 @@ impl Interactivity {
.push(Box::new(move |event, bounds, phase, cx| {
if phase == DispatchPhase::Capture
&& event.button == button
&& !bounds.visibly_contains(&event.position, cx)
&& !bounds.did_visibly_contains(&event.position, cx)
{
(listener)(event, cx);
}
@ -228,7 +237,9 @@ impl Interactivity {
) {
self.mouse_move_listeners
.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);
}
}));
@ -277,7 +288,9 @@ impl Interactivity {
) {
self.scroll_wheel_listeners
.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);
}
}));
@ -564,7 +577,7 @@ pub trait InteractiveElement: Sized {
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
/// in the [`VisualTestContext::debug_bounds`] map
/// This is a noop in release builds
@ -573,14 +586,14 @@ pub trait InteractiveElement: Sized {
self
}
#[cfg(not(any(test, feature = "test-support")))]
/// Set a key that can be used to look up this element's bounds
/// in the [`VisualTestContext::debug_bounds`] map
/// This is a noop in release builds
#[inline]
fn debug_selector(self, _: impl FnOnce() -> String) -> Self {
self
}
// #[cfg(not(any(test, feature = "test-support")))]
// /// Set a key that can be used to look up this element's bounds
// /// in the [`VisualTestContext::debug_bounds`] map
// /// This is a noop in release builds
// #[inline]
// fn debug_selector(self, _: impl FnOnce() -> String) -> Self {
// self
// }
/// 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`]
@ -1072,6 +1085,7 @@ impl Element for Div {
})
},
);
(
layout_id,
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(
&mut self,
bounds: Bounds<Pixels>,
@ -1207,7 +1245,7 @@ pub struct Interactivity {
#[cfg(debug_assertions)]
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>,
}
@ -1222,7 +1260,7 @@ pub struct InteractiveBounds {
impl InteractiveBounds {
/// 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)
}
@ -1230,7 +1268,7 @@ impl InteractiveBounds {
/// under an active drag
pub fn drag_target_contains(&self, point: &Point<Pixels>, cx: &WindowContext) -> bool {
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)
}
/// 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
/// and bind the element's mouse and keyboard events.
///
@ -1288,11 +1349,8 @@ impl Interactivity {
content_size: Size<Pixels>,
element_state: &mut InteractiveElementState,
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))]
if let Some(debug_selector) = &self.debug_selector {
cx.window
@ -1301,8 +1359,8 @@ impl Interactivity {
.insert(debug_selector.clone(), bounds);
}
let paint_hover_group_handler = |cx: &mut ElementContext| {
let hover_group_bounds = self
let paint_hover_group_handler = |this: &Self, cx: &mut ElementContext| {
let hover_group_bounds = this
.group_hover_style
.as_ref()
.and_then(|group_hover| GroupBounds::get(&group_hover.group, cx));
@ -1319,12 +1377,15 @@ impl Interactivity {
}
};
if style.visibility == Visibility::Hidden {
cx.with_z_index(z_index, |cx| paint_hover_group_handler(cx));
return;
}
let z_index = self.base_style.z_index.unwrap_or(0);
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| {
cx.with_text_style(style.text_style().cloned(), |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(),
};
if self.block_mouse
|| style.background.as_ref().is_some_and(|fill| {
fill.color().is_some_and(|color| !color.is_transparent())
})
{
cx.add_opaque_layer(interactive_bounds.bounds);
}
// if self.block_mouse
// || style.background.as_ref().is_some_and(|fill| {
// fill.color().is_some_and(|color| !color.is_transparent())
// })
// {
// cx.add_opaque_layer(interactive_bounds.bounds);
// }
if !cx.has_active_drag() {
if let Some(mouse_cursor) = style.mouse_cursor {
let mouse_position = &cx.mouse_position();
let hovered =
interactive_bounds.visibly_contains(mouse_position, cx);
interactive_bounds.did_visibly_contains(mouse_position, cx);
if hovered {
cx.set_cursor_style(mouse_cursor);
}
@ -1467,7 +1528,8 @@ impl Interactivity {
move |event: &MouseDownEvent, phase, cx| {
if phase == DispatchPhase::Bubble
&& !cx.default_prevented()
&& interactive_bounds.visibly_contains(&event.position, cx)
&& interactive_bounds
.did_visibly_contains(&event.position, cx)
{
cx.focus(&focus_handle);
// 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()
|| self.base_style.mouse_cursor.is_some()
@ -1585,7 +1647,8 @@ impl Interactivity {
move |event: &MouseDownEvent, phase, cx| {
if phase == DispatchPhase::Bubble
&& 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());
cx.refresh();
@ -1646,7 +1709,7 @@ impl Interactivity {
DispatchPhase::Bubble => {
if let Some(mouse_down) = captured_mouse_down.take() {
if interactive_bounds
.visibly_contains(&event.position, cx)
.did_visibly_contains(&event.position, cx)
{
let mouse_click = ClickEvent {
down: mouse_down,
@ -1678,7 +1741,7 @@ impl Interactivity {
return;
}
let is_hovered = interactive_bounds
.visibly_contains(&event.position, cx)
.did_visibly_contains(&event.position, cx)
&& has_mouse_down.borrow().is_none()
&& !cx.has_active_drag();
let mut was_hovered = was_hovered.borrow_mut();
@ -1705,7 +1768,7 @@ impl Interactivity {
cx.on_mouse_event(move |event: &MouseMoveEvent, phase, cx| {
let is_hovered = interactive_bounds
.visibly_contains(&event.position, cx)
.did_visibly_contains(&event.position, cx)
&& pending_mouse_down.borrow().is_none();
if !is_hovered {
active_tooltip.borrow_mut().take();
@ -1787,7 +1850,7 @@ impl Interactivity {
let group = active_group_bounds
.map_or(false, |bounds| bounds.contains(&down.position));
let element =
interactive_bounds.visibly_contains(&down.position, cx);
interactive_bounds.did_visibly_contains(&down.position, cx);
if group || element {
*active_state.borrow_mut() =
ElementClickedState { group, element };
@ -1840,7 +1903,7 @@ impl Interactivity {
let interactive_bounds = interactive_bounds.clone();
cx.on_mouse_event(move |event: &ScrollWheelEvent, phase, cx| {
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 old_scroll_offset = *scroll_offset;
@ -1910,7 +1973,7 @@ impl Interactivity {
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();
style.refine(&self.base_style);
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(in_focus_style) = self.in_focus_style.as_ref() {
if focus_handle.within_focused(cx) {
style.refine(in_focus_style);
// 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(in_focus_style) = self.in_focus_style.as_ref() {
if focus_handle.within_focused(cx) {
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 focus_handle.is_focused(cx) {
style.refine(focus_style);
if let Some(hover_style) = self.hover_style.as_ref() {
let outer_button = self.debug_selector.as_deref() == Some("outer_button");
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 {
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(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_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()
&& bounds
.intersect(&cx.content_mask().bounds)
.contains(&mouse_position)
&& cx.was_top_layer_under_active_drag(
&mouse_position,
cx.stacking_order(),
)
&& group_bounds.contains(&mouse_position)
{
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
.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)
}
cx.active_drag = Some(drag);
}
}
if let Some(active_style) = self.active_style.as_ref() {
if clicked_state.element {
style.refine(active_style)
}
let clicked_state = element_state
.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() {
if clicked_state.element {
style.refine(active_style)
}
}
// });
style
}
@ -2211,6 +2280,15 @@ where
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) {
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| {
if phase == DispatchPhase::Bubble
&& 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(
&scroll_top,

View file

@ -427,7 +427,7 @@ impl Element for InteractiveText {
.clickable_ranges
.iter()
.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)
}

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) {
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 {
model: AnyModel,
request_layout: fn(&AnyView, &mut ElementContext) -> (LayoutId, AnyElement),
post_layout: fn(&mut AnyElement, &mut ElementContext),
cache: bool,
}
@ -220,7 +221,8 @@ impl AnyView {
pub fn downgrade(&self) -> AnyWeakView {
AnyWeakView {
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 {
model,
request_layout: self.request_layout,
post_layout: self.post_layout,
cache: self.cache,
}),
}
@ -247,20 +250,34 @@ impl AnyView {
self.model.entity_id()
}
pub(crate) fn draw(
pub(crate) fn layout_and_post_layout(
&self,
origin: Point<Pixels>,
available_space: Size<AvailableSpace>,
cx: &mut ElementContext,
) {
cx.paint_view(self.entity_id(), |cx| {
) -> AnyElement {
cx.with_view(self.entity_id(), |cx| {
cx.with_absolute_element_offset(origin, |cx| {
let (layout_id, mut rendered_element) = (self.request_layout)(self, cx);
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 {
@ -268,6 +285,7 @@ impl<V: Render> From<View<V>> for AnyView {
AnyView {
model: value.model.into_any(),
request_layout: any_view::request_layout::<V>,
post_layout: any_view::post_layout,
cache: false,
}
}
@ -300,9 +318,19 @@ impl Element for AnyView {
(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) {
cx.paint_view(self.entity_id(), |cx| {
cx.with_view(self.entity_id(), |cx| {
if !self.cache {
state.element.take().unwrap().paint(cx);
return;
@ -328,13 +356,8 @@ impl Element for AnyView {
element.draw(bounds.origin, bounds.size.into(), cx);
}
state.next_stacking_order_id = cx
.window
.next_frame
.next_stacking_order_ids
.last()
.copied()
.unwrap();
state.next_stacking_order_id =
cx.window.next_stacking_order_ids.last().copied().unwrap();
state.cache_key = Some(ViewCacheKey {
bounds,
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.
pub struct AnyWeakView {
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 {
@ -381,7 +405,8 @@ impl AnyWeakView {
let model = self.model.upgrade()?;
Some(AnyView {
model,
request_layout: self.layout,
request_layout: self.request_layout,
post_layout: self.post_layout,
cache: false,
})
}
@ -391,7 +416,8 @@ impl<V: 'static + Render> From<WeakView<V>> for AnyWeakView {
fn from(view: WeakView<V>) -> Self {
Self {
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);
(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) rendered_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>>>,
pub(crate) dirty_views: FxHashSet<EntityId>,
pub(crate) focus_handles: Arc<RwLock<SlotMap<FocusId, AtomicUsize>>>,
@ -441,6 +444,9 @@ impl Window {
element_id_stack: GlobalElementId::default(),
rendered_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,
dirty_views: FxHashSet::default(),
focus_handles: Arc::new(RwLock::new(SlotMap::with_key())),
@ -466,6 +472,7 @@ impl Window {
graphics_profiler_enabled: false,
}
}
fn new_focus_listener(
&mut self,
value: AnyWindowFocusListener,
@ -848,6 +855,49 @@ impl<'a> WindowContext<'a> {
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
/// on top of the given level. Layers who are extensions of the queried layer
/// are not considered to be on top of queried layer.
@ -871,27 +921,65 @@ impl<'a> WindowContext<'a> {
// 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);
// 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;
}
// if !is_on_same_layer {
// return false;
// }
return false;
}
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,
point: &Point<Pixels>,
layer: &StackingOrder,
) -> bool {
// 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 {
// 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.
@ -919,14 +1007,15 @@ impl<'a> WindowContext<'a> {
// 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);
// 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;
}
// if !is_on_same_layer {
// return false;
// }
return false;
}
true
@ -934,7 +1023,7 @@ impl<'a> WindowContext<'a> {
/// Called during painting to get the current stacking order.
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
@ -950,6 +1039,48 @@ impl<'a> WindowContext<'a> {
}
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| {
cx.with_z_index(0, |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.draw(Point::default(), available_space, cx);
root_view.paint(Point::default(), root_element, cx);
})
})
});
if let Some(active_drag) = self.app.active_drag.take() {
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);
active_drag.view.draw(offset, available_space, cx);
})
active_drag
.view
.paint(offset, drag_or_tooltip_element.unwrap(), cx);
});
});
self.active_drag = Some(active_drag);
} else if let Some(tooltip_request) = self.window.next_frame.tooltip_request.take() {
} 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);
tooltip_request.tooltip.view.draw(
tooltip_request.tooltip.view.paint(
tooltip_request.tooltip.cursor_offset,
available_space,
drag_or_tooltip_element.unwrap(),
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
@ -1046,6 +1176,9 @@ impl<'a> WindowContext<'a> {
let previous_window_active = self.window.rendered_frame.window_active;
mem::swap(&mut self.window.rendered_frame, &mut self.window.next_frame);
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_window_active = self.window.rendered_frame.window_active;
@ -1078,6 +1211,8 @@ impl<'a> WindowContext<'a> {
}
self.window.refreshing = false;
self.window.drawing = false;
println!("\n\n\n\n");
}
fn present(&self) {

View file

@ -59,9 +59,6 @@ pub(crate) struct Frame {
pub(crate) dispatch_tree: DispatchTree,
pub(crate) scene: Scene,
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) element_offset_stack: Vec<Point<Pixels>>,
pub(crate) requested_input_handler: Option<RequestedInputHandler>,
@ -85,9 +82,6 @@ impl Frame {
dispatch_tree,
scene: Scene::default(),
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(),
element_offset_stack: Vec::new(),
requested_input_handler: None,
@ -107,8 +101,6 @@ impl Frame {
self.mouse_listeners.values_mut().for_each(Vec::clear);
self.dispatch_tree.clear();
self.depth_map.clear();
self.next_stacking_order_ids = vec![0];
self.next_root_z_index = 0;
self.reused_views.clear();
self.scene.clear();
self.requested_input_handler.take();
@ -318,6 +310,7 @@ impl<'a> ElementContext<'a> {
.next_frame
.dispatch_tree
.reuse_view(view_id, &mut self.cx.window.rendered_frame.dispatch_tree);
for view_id in grafted_view_ids {
assert!(self.window.next_frame.reused_views.insert(view_id));
@ -353,21 +346,9 @@ impl<'a> ElementContext<'a> {
}
debug_assert!(
next_stacking_order_id
>= self
.window
.next_frame
.next_stacking_order_ids
.last()
.copied()
.unwrap()
next_stacking_order_id >= self.window.next_stacking_order_ids.last().copied().unwrap()
);
*self
.window
.next_frame
.next_stacking_order_ids
.last_mut()
.unwrap() = next_stacking_order_id;
*self.window.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.
@ -440,6 +421,7 @@ impl<'a> ElementContext<'a> {
/// Invoke the given function with the content mask reset to that
/// 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 {
let mask = ContentMask {
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(
self.window_mut()
.next_frame
.next_stacking_order_ids
.last_mut()
.unwrap(),
@ -461,13 +442,13 @@ impl<'a> ElementContext<'a> {
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);
let result = f(self);
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
}
@ -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 {
let new_stacking_order_id = post_inc(
self.window_mut()
.next_frame
.next_stacking_order_ids
.last_mut()
.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 {
z_index,
id: new_stacking_order_id,
};
self.window_mut().next_frame.z_index_stack.push(new_context);
let result = f(self);
self.window_mut().next_frame.z_index_stack.pop();
self.window_mut().z_index_stack.push(new_context);
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
}
@ -667,7 +655,7 @@ impl<'a> ElementContext<'a> {
shadow_bounds.origin += shadow.offset;
shadow_bounds.dilate(shadow.spread_radius);
window.next_frame.scene.insert(
&window.next_frame.z_index_stack,
&window.z_index_stack,
Shadow {
view_id: view_id.into(),
layer_id: 0,
@ -693,7 +681,7 @@ impl<'a> ElementContext<'a> {
let window = &mut *self.window;
window.next_frame.scene.insert(
&window.next_frame.z_index_stack,
&window.z_index_stack,
Quad {
view_id: view_id.into(),
layer_id: 0,
@ -721,7 +709,7 @@ impl<'a> ElementContext<'a> {
window
.next_frame
.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.
@ -746,7 +734,7 @@ impl<'a> ElementContext<'a> {
let window = &mut *self.window;
window.next_frame.scene.insert(
&window.next_frame.z_index_stack,
&window.z_index_stack,
Underline {
view_id: view_id.into(),
layer_id: 0,
@ -778,7 +766,7 @@ impl<'a> ElementContext<'a> {
let window = &mut *self.window;
window.next_frame.scene.insert(
&window.next_frame.z_index_stack,
&window.z_index_stack,
Underline {
view_id: view_id.into(),
layer_id: 0,
@ -838,7 +826,7 @@ impl<'a> ElementContext<'a> {
let view_id = self.parent_view_id();
let window = &mut *self.window;
window.next_frame.scene.insert(
&window.next_frame.z_index_stack,
&window.z_index_stack,
MonochromeSprite {
view_id: view_id.into(),
layer_id: 0,
@ -896,7 +884,7 @@ impl<'a> ElementContext<'a> {
let window = &mut *self.window;
window.next_frame.scene.insert(
&window.next_frame.z_index_stack,
&window.z_index_stack,
PolychromeSprite {
view_id: view_id.into(),
layer_id: 0,
@ -942,7 +930,7 @@ impl<'a> ElementContext<'a> {
let window = &mut *self.window;
window.next_frame.scene.insert(
&window.next_frame.z_index_stack,
&window.z_index_stack,
MonochromeSprite {
view_id: view_id.into(),
layer_id: 0,
@ -981,7 +969,7 @@ impl<'a> ElementContext<'a> {
let window = &mut *self.window;
window.next_frame.scene.insert(
&window.next_frame.z_index_stack,
&window.z_index_stack,
PolychromeSprite {
view_id: view_id.into(),
layer_id: 0,
@ -1006,7 +994,7 @@ impl<'a> ElementContext<'a> {
let view_id = self.parent_view_id();
let window = &mut *self.window;
window.next_frame.scene.insert(
&window.next_frame.z_index_stack,
&window.z_index_stack,
crate::Surface {
view_id: view_id.into(),
layer_id: 0,
@ -1092,9 +1080,10 @@ impl<'a> ElementContext<'a> {
.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>) {
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 depth_map = &mut self.window.next_frame.depth_map;
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.
/// 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 {
/// This is a fairly low-level method used to in the post-layout and paint phase of views.
pub fn with_view<R>(&mut self, view_id: EntityId, f: impl FnOnce(&mut Self) -> R) -> R {
let text_system = self.text_system().clone();
text_system.with_view(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,
) {
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
.next_frame
.mouse_listeners

View file

@ -10,37 +10,49 @@ impl Render for ZIndexStory {
fn render(&mut self, _cx: &mut ViewContext<Self>) -> impl IntoElement {
Story::container().child(Story::title("z-index")).child(
div()
.flex()
.debug_selector(|| "outer_button".into())
.size_20()
.bg(gpui::red())
.hover(|s| s.bg(gpui::green()))
.child(
div()
.w(px(250.))
.child(Story::label("z-index: auto"))
.child(ZIndexExample::new(0)),
)
.child(
div()
.w(px(250.))
.child(Story::label("z-index: 1"))
.child(ZIndexExample::new(1)),
)
.child(
div()
.w(px(250.))
.child(Story::label("z-index: 3"))
.child(ZIndexExample::new(3)),
)
.child(
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)),
),
.debug_selector(|| "inner_button".into())
.z_index(0)
.size_8()
.bg(gpui::yellow())
.hover(|s| s.bg(gpui::blue())),
), // div()
// .flex()
// .child(
// div()
// .w(px(250.))
// .child(Story::label("z-index: auto"))
// .child(ZIndexExample::new(0)),
// )
// .child(
// div()
// .w(px(250.))
// .child(Story::label("z-index: 1"))
// .child(ZIndexExample::new(1)),
// )
// .child(
// div()
// .w(px(250.))
// .child(Story::label("z-index: 3"))
// .child(ZIndexExample::new(3)),
// )
// .child(
// 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");
let args = Args::parse();
// let args = Args::parse();
let story_selector = args.story.clone().unwrap_or_else(|| {
let stories = ComponentStory::iter().collect::<Vec<_>>();
// let story_selector = args.story.clone().unwrap_or_else(|| {
// let stories = ComponentStory::iter().collect::<Vec<_>>();
ctrlc::set_handler(move || {}).unwrap();
// ctrlc::set_handler(move || {}).unwrap();
let result = FuzzySelect::new()
.with_prompt("Choose a story to run:")
.items(&stories)
.interact();
// let result = FuzzySelect::new()
// .with_prompt("Choose a story to run:")
// .items(&stories)
// .interact();
let Ok(selection) = result else {
dialoguer::console::Term::stderr().show_cursor().unwrap();
std::process::exit(0);
};
// let Ok(selection) = result else {
// dialoguer::console::Term::stderr().show_cursor().unwrap();
// std::process::exit(0);
// };
StorySelector::Component(stories[selection])
});
let theme_name = args.theme.unwrap_or("One Dark".to_string());
// StorySelector::Component(stories[selection])
// });
// 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| {
load_embedded_fonts(cx).unwrap();
@ -69,7 +70,7 @@ fn main() {
theme::init(theme::LoadThemes::All(Box::new(Assets)), cx);
let selector = story_selector;
// let selector = story_selector;
let theme_registry = ThemeRegistry::global(cx);
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;
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,
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() {
cx.set_cursor_style(gpui::CursorStyle::PointingHand)
} else {
@ -658,7 +658,7 @@ impl TerminalElement {
}
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| {
if !terminal.selection_started() {
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.mouse_move(&e, origin);
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.
cx.on_mouse_event(move |e: &MouseDownEvent, phase, cx| {
if phase == DispatchPhase::Bubble
&& interactive_bounds.visibly_contains(&e.position, cx)
&& interactive_bounds.did_visibly_contains(&e.position, cx)
{
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| {
if phase == DispatchPhase::Bubble
&& event.button == MouseButton::Right
&& interactive_bounds.visibly_contains(&event.position, cx)
&& interactive_bounds.did_visibly_contains(&event.position, cx)
{
cx.stop_propagation();
cx.prevent_default();

View file

@ -758,7 +758,7 @@ mod element {
bounds: handle_bounds,
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 {
Axis::Vertical => CursorStyle::ResizeUpDown,
Axis::Horizontal => CursorStyle::ResizeLeftRight,