From 825a8f0927c17baa14b67c8d5ea1d212e2294350 Mon Sep 17 00:00:00 2001 From: Kirill Bulatov Date: Mon, 18 Dec 2023 19:15:54 +0200 Subject: [PATCH] Initial fix of the z-index Co-Authored-By: Antonio Scandurra Co-Authored-By: Nathan Sobo --- crates/gpui2/src/elements/div.rs | 12 +- crates/gpui2/src/scene.rs | 153 ++++++++++++++------ crates/gpui2/src/window.rs | 75 ++++++++-- crates/ui2/src/components/list/list_item.rs | 4 +- crates/workspace2/src/toolbar.rs | 2 + 5 files changed, 181 insertions(+), 65 deletions(-) diff --git a/crates/gpui2/src/elements/div.rs b/crates/gpui2/src/elements/div.rs index 0d477fc62d..6e9c95e19f 100644 --- a/crates/gpui2/src/elements/div.rs +++ b/crates/gpui2/src/elements/div.rs @@ -1447,9 +1447,15 @@ impl Interactivity { cx.on_action(action_type, listener) } - f(style, scroll_offset.unwrap_or_default(), cx) - }, - ); + cx.with_z_index(style.z_index.unwrap_or(0), |cx| { + if style.background.as_ref().is_some_and(|fill| { + fill.color().is_some_and(|color| !color.is_transparent()) + }) { + cx.add_opaque_layer(bounds) + }f(style, scroll_offset.unwrap_or_default(), cx) + }) + }, + ); if let Some(group) = self.group.as_ref() { GroupBounds::pop(group, cx); diff --git a/crates/gpui2/src/scene.rs b/crates/gpui2/src/scene.rs index 68c068dfe9..15a4a37d5b 100644 --- a/crates/gpui2/src/scene.rs +++ b/crates/gpui2/src/scene.rs @@ -857,55 +857,116 @@ impl Bounds { } } -// #[cfg(test)] -// mod tests { -// use crate::{point, size}; +#[cfg(test)] +mod tests { + use super::*; + use crate::{point, px, size, Size}; + use smallvec::smallvec; -// use super::*; -// use smallvec::smallvec; + // todo!() + // #[test] + // fn test_scene() { + // let mut scene = SceneBuilder::default(); + // assert_eq!(scene.layers_by_order.len(), 0); -// #[test] -// fn test_scene() { -// let mut scene = SceneBuilder::new(); -// assert_eq!(scene.layers_by_order.len(), 0); + // // div with z_index(1) + // // glyph with z_index(1) + // // div with z_index(1) + // // glyph with z_index(1) -// scene.insert(&smallvec![1].into(), quad()); -// scene.insert(&smallvec![2].into(), shadow()); -// scene.insert(&smallvec![3].into(), quad()); + // scene.insert( + // &smallvec![1].into(), + // quad( + // point(px(0.), px(0.)), + // size(px(100.), px(100.)), + // crate::black(), + // ), + // ); + // scene.insert( + // &smallvec![1, 1].into(), + // sprite( + // point(px(0.), px(0.)), + // size(px(10.), px(10.)), + // crate::white(), + // ), + // ); + // scene.insert( + // &smallvec![1].into(), + // quad( + // point(px(10.), px(10.)), + // size(px(20.), px(20.)), + // crate::green(), + // ), + // ); + // scene.insert( + // &smallvec![1, 1].into(), + // sprite(point(px(15.), px(15.)), size(px(5.), px(5.)), crate::blue()), + // ); -// let mut batches_count = 0; -// for _ in scene.build().batches() { -// batches_count += 1; -// } -// assert_eq!(batches_count, 3); -// } + // assert!(!scene.layers_by_order.is_empty()); -// fn quad() -> Quad { -// Quad { -// order: 0, -// bounds: Bounds { -// origin: point(ScaledPixels(0.), ScaledPixels(0.)), -// size: size(ScaledPixels(100.), ScaledPixels(100.)), -// }, -// content_mask: Default::default(), -// background: Default::default(), -// border_color: Default::default(), -// corner_radii: Default::default(), -// border_widths: Default::default(), -// } -// } + // for batch in scene.build().batches() { + // println!("new batch"); + // match batch { + // PrimitiveBatch::Quads(quads) => { + // for quad in quads { + // if quad.background == crate::black() { + // println!(" black quad"); + // } else if quad.background == crate::green() { + // println!(" green quad"); + // } else { + // todo!(" ((( bad quad"); + // } + // } + // } + // PrimitiveBatch::MonochromeSprites { sprites, .. } => { + // for sprite in sprites { + // if sprite.color == crate::white() { + // println!(" white sprite"); + // } else if sprite.color == crate::blue() { + // println!(" blue sprite"); + // } else { + // todo!(" ((( bad sprite") + // } + // } + // } + // _ => todo!(), + // } + // } + // } -// fn shadow() -> Shadow { -// Shadow { -// order: Default::default(), -// bounds: Bounds { -// origin: point(ScaledPixels(0.), ScaledPixels(0.)), -// size: size(ScaledPixels(100.), ScaledPixels(100.)), -// }, -// corner_radii: Default::default(), -// content_mask: Default::default(), -// color: Default::default(), -// blur_radius: Default::default(), -// } -// } -// } + fn quad(origin: Point, size: Size, background: Hsla) -> Quad { + Quad { + order: 0, + bounds: Bounds { origin, size }.scale(1.), + background, + content_mask: ContentMask { + bounds: Bounds { origin, size }, + } + .scale(1.), + border_color: Default::default(), + corner_radii: Default::default(), + border_widths: Default::default(), + } + } + + fn sprite(origin: Point, size: Size, color: Hsla) -> MonochromeSprite { + MonochromeSprite { + order: 0, + bounds: Bounds { origin, size }.scale(1.), + content_mask: ContentMask { + bounds: Bounds { origin, size }, + } + .scale(1.), + color, + tile: AtlasTile { + texture_id: AtlasTextureId { + index: 0, + kind: crate::AtlasTextureKind::Monochrome, + }, + tile_id: crate::TileId(0), + bounds: Default::default(), + }, + } + } +} diff --git a/crates/gpui2/src/window.rs b/crates/gpui2/src/window.rs index f7ebddd0fe..5d06cfe1a5 100644 --- a/crates/gpui2/src/window.rs +++ b/crates/gpui2/src/window.rs @@ -39,24 +39,36 @@ use std::{ Arc, }, }; -use util::ResultExt; +use util::{post_inc, ResultExt}; const ACTIVE_DRAG_Z_INDEX: u8 = 1; /// A global stacking order, which is created by stacking successive z-index values. /// Each z-index will always be interpreted in the context of its parent z-index. -#[derive(Deref, DerefMut, Clone, Debug, Ord, PartialOrd, PartialEq, Eq)] +#[derive(Deref, DerefMut, Clone, Ord, PartialOrd, PartialEq, Eq, Default)] pub struct StackingOrder { #[deref] #[deref_mut] - z_indices: SmallVec<[u8; 64]>, + context_stack: SmallVec<[StackingContext; 64]>, } -impl Default for StackingOrder { - fn default() -> Self { - StackingOrder { - z_indices: SmallVec::new(), +#[derive(Clone, Ord, PartialOrd, PartialEq, Eq)] +pub struct StackingContext { + // TODO kb use u16 and/or try to push the `id` above into the stacking order + z_index: u8, + id: u16, +} + +impl std::fmt::Debug for StackingOrder { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let mut stacks = self.context_stack.iter().peekable(); + while let Some(z_index) = stacks.next() { + write!(f, "{}.{}", z_index.z_index, z_index.id)?; + if stacks.peek().is_some() { + write!(f, "->")?; + } } + Ok(()) } } @@ -284,6 +296,7 @@ pub(crate) struct Frame { pub(crate) scene_builder: SceneBuilder, pub(crate) depth_map: Vec<(StackingOrder, Bounds)>, pub(crate) z_index_stack: StackingOrder, + pub(crate) stacking_context_id_stack: Vec, content_mask_stack: Vec>, element_offset_stack: Vec>, } @@ -297,6 +310,7 @@ impl Frame { dispatch_tree, scene_builder: SceneBuilder::default(), z_index_stack: StackingOrder::default(), + stacking_context_id_stack: vec![0], depth_map: Default::default(), content_mask_stack: Vec::new(), element_offset_stack: Vec::new(), @@ -308,6 +322,8 @@ impl Frame { self.mouse_listeners.values_mut().for_each(Vec::clear); self.dispatch_tree.clear(); self.depth_map.clear(); + self.stacking_context_id_stack.clear(); + self.stacking_context_id_stack.push(0); } fn focus_path(&self) -> SmallVec<[FocusId; 8]> { @@ -931,8 +947,20 @@ impl<'a> WindowContext<'a> { /// Called during painting to invoke the given closure in a new stacking context. The given /// z-index is interpreted relative to the previous call to `stack`. pub fn with_z_index(&mut self, z_index: u8, f: impl FnOnce(&mut Self) -> R) -> R { - self.window.next_frame.z_index_stack.push(z_index); + let id = post_inc( + self.window + .next_frame + .stacking_context_id_stack + .last_mut() + .unwrap(), + ); + self.window.next_frame.stacking_context_id_stack.push(0); + self.window + .next_frame + .z_index_stack + .push(StackingContext { z_index, id }); let result = f(self); + self.window.next_frame.stacking_context_id_stack.pop(); self.window.next_frame.z_index_stack.pop(); result } @@ -2046,6 +2074,30 @@ pub trait BorrowWindow: BorrowMut + BorrowMut { result } + /// Called during painting to invoke the given closure in a new stacking context. The given + /// z-index is interpreted relative to the previous call to `stack`. + fn with_z_index(&mut self, z_index: u8, f: impl FnOnce(&mut Self) -> R) -> R { + let id = post_inc( + self.window_mut() + .next_frame + .stacking_context_id_stack + .last_mut() + .unwrap(), + ); + self.window_mut() + .next_frame + .stacking_context_id_stack + .push(0); + self.window_mut() + .next_frame + .z_index_stack + .push(StackingContext { z_index, id }); + let result = f(self); + self.window_mut().next_frame.stacking_context_id_stack.pop(); + self.window_mut().next_frame.z_index_stack.pop(); + result + } + /// Update the global element offset relative to the current offset. This is used to implement /// scrolling. fn with_element_offset( @@ -2269,13 +2321,6 @@ impl<'a, V: 'static> ViewContext<'a, V> { &mut self.window_cx } - pub fn with_z_index(&mut self, z_index: u8, f: impl FnOnce(&mut Self) -> R) -> R { - self.window.next_frame.z_index_stack.push(z_index); - let result = f(self); - self.window.next_frame.z_index_stack.pop(); - result - } - pub fn on_next_frame(&mut self, f: impl FnOnce(&mut V, &mut ViewContext) + 'static) where V: 'static, diff --git a/crates/ui2/src/components/list/list_item.rs b/crates/ui2/src/components/list/list_item.rs index bdb5c2b854..a6f9935053 100644 --- a/crates/ui2/src/components/list/list_item.rs +++ b/crates/ui2/src/components/list/list_item.rs @@ -129,6 +129,7 @@ impl RenderOnce for ListItem { fn render(self, cx: &mut WindowContext) -> Self::Rendered { h_stack() .id(self.id) + .bg(gpui::green()) .w_full() .relative() // When an item is inset draw the indent spacing outside of the item @@ -171,7 +172,8 @@ impl RenderOnce for ListItem { }) }) .when_some(self.on_click, |this, on_click| { - this.cursor_pointer().on_click(on_click) + this.cursor_copy() + .on_click(move |event, cx| on_click(dbg!(event), cx)) }) .when_some(self.on_secondary_mouse_down, |this, on_mouse_down| { this.on_mouse_down(MouseButton::Right, move |event, cx| { diff --git a/crates/workspace2/src/toolbar.rs b/crates/workspace2/src/toolbar.rs index cd25582f36..f83879a64e 100644 --- a/crates/workspace2/src/toolbar.rs +++ b/crates/workspace2/src/toolbar.rs @@ -105,6 +105,8 @@ impl Render for Toolbar { v_stack() .p_1() .gap_2() + // todo!() use a proper constant here (ask Marshall & Nate) + .z_index(80) .border_b() .border_color(cx.theme().colors().border_variant) .bg(cx.theme().colors().toolbar_background)