Detailed changes
@@ -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);
@@ -857,55 +857,116 @@ impl Bounds<ScaledPixels> {
}
}
-// #[cfg(test)]
-// mod tests {
-// use crate::{point, size};
-
-// use super::*;
-// use smallvec::smallvec;
-
-// #[test]
-// fn test_scene() {
-// let mut scene = SceneBuilder::new();
-// assert_eq!(scene.layers_by_order.len(), 0);
-
-// scene.insert(&smallvec![1].into(), quad());
-// scene.insert(&smallvec![2].into(), shadow());
-// scene.insert(&smallvec![3].into(), quad());
-
-// let mut batches_count = 0;
-// for _ in scene.build().batches() {
-// batches_count += 1;
-// }
-// assert_eq!(batches_count, 3);
-// }
-
-// 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(),
-// }
-// }
-
-// 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(),
-// }
-// }
-// }
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use crate::{point, px, size, Size};
+ use smallvec::smallvec;
+
+ // todo!()
+ // #[test]
+ // fn test_scene() {
+ // let mut scene = SceneBuilder::default();
+ // 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(
+ // 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()),
+ // );
+
+ // assert!(!scene.layers_by_order.is_empty());
+
+ // 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 quad(origin: Point<Pixels>, size: Size<Pixels>, 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<Pixels>, size: Size<Pixels>, 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(),
+ },
+ }
+ }
+}
@@ -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<Pixels>)>,
pub(crate) z_index_stack: StackingOrder,
+ pub(crate) stacking_context_id_stack: Vec<u16>,
content_mask_stack: Vec<ContentMask<Pixels>>,
element_offset_stack: Vec<Point<Pixels>>,
}
@@ -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<R>(&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<Window> + BorrowMut<AppContext> {
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<R>(&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<R>(
@@ -2269,13 +2321,6 @@ impl<'a, V: 'static> ViewContext<'a, V> {
&mut self.window_cx
}
- pub fn with_z_index<R>(&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<V>) + 'static)
where
V: 'static,
@@ -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| {
@@ -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)