Better display items from different sources with different z-indices in the same place (#3723)

This commit is contained in:
Kirill Bulatov 2023-12-20 00:01:37 +02:00 committed by GitHub
commit acbb3f39f6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 47 additions and 83 deletions

View file

@ -68,6 +68,7 @@ impl Render for CollabTitlebarItem {
h_stack()
.id("titlebar")
.z_index(160) // todo!("z-index")
.justify_between()
.w_full()
.h(rems(1.75))

View file

@ -1447,7 +1447,14 @@ 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)
})
},
);

View file

@ -1,7 +1,7 @@
use std::sync::Arc;
use crate::{
point, size, Bounds, DevicePixels, Element, ImageData, InteractiveElement,
point, size, BorrowWindow, Bounds, DevicePixels, Element, ImageData, InteractiveElement,
InteractiveElementState, Interactivity, IntoElement, LayoutId, Pixels, SharedString, Size,
StyleRefinement, Styled, WindowContext,
};

View file

@ -856,56 +856,3 @@ impl Bounds<ScaledPixels> {
.expect("Polygon should not be empty")
}
}
// #[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(),
// }
// }
// }

View file

@ -39,24 +39,32 @@ 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<[u8; 64]>,
id: u32,
}
impl Default for StackingOrder {
fn default() -> Self {
StackingOrder {
z_indices: SmallVec::new(),
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();
write!(f, "[({}): ", self.id)?;
while let Some(z_index) = stacks.next() {
write!(f, "{z_index}")?;
if stacks.peek().is_some() {
write!(f, "->")?;
}
}
write!(f, "]")?;
Ok(())
}
}
@ -284,6 +292,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) next_stacking_order_id: u32,
content_mask_stack: Vec<ContentMask<Pixels>>,
element_offset_stack: Vec<Point<Pixels>>,
}
@ -297,6 +306,7 @@ impl Frame {
dispatch_tree,
scene_builder: SceneBuilder::default(),
z_index_stack: StackingOrder::default(),
next_stacking_order_id: 0,
depth_map: Default::default(),
content_mask_stack: Vec::new(),
element_offset_stack: Vec::new(),
@ -308,6 +318,7 @@ impl Frame {
self.mouse_listeners.values_mut().for_each(Vec::clear);
self.dispatch_tree.clear();
self.depth_map.clear();
self.next_stacking_order_id = 0;
}
fn focus_path(&self) -> SmallVec<[FocusId; 8]> {
@ -928,15 +939,6 @@ impl<'a> WindowContext<'a> {
self.window.requested_cursor_style = Some(style)
}
/// 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 result = f(self);
self.window.next_frame.z_index_stack.pop();
result
}
/// Called during painting to track which z-index is on top at each pixel position
pub fn add_opaque_layer(&mut self, bounds: Bounds<Pixels>) {
let stacking_order = self.window.next_frame.z_index_stack.clone();
@ -2046,6 +2048,18 @@ 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 new_stacking_order_id =
post_inc(&mut self.window_mut().next_frame.next_stacking_order_id);
self.window_mut().next_frame.z_index_stack.id = new_stacking_order_id;
self.window_mut().next_frame.z_index_stack.push(z_index);
let result = f(self);
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 +2283,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,

View file

@ -1,11 +1,11 @@
use editor::{Cursor, HighlightedRange, HighlightedRangeLine};
use gpui::{
black, div, fill, point, px, red, relative, AnyElement, AsyncWindowContext, AvailableSpace,
Bounds, DispatchPhase, Element, ElementId, ExternalPaths, FocusHandle, Font, FontStyle,
FontWeight, HighlightStyle, Hsla, InteractiveElement, InteractiveElementState, Interactivity,
IntoElement, LayoutId, Model, ModelContext, ModifiersChangedEvent, MouseButton, Pixels,
PlatformInputHandler, Point, Rgba, ShapedLine, Size, StatefulInteractiveElement, Styled,
TextRun, TextStyle, TextSystem, UnderlineStyle, WhiteSpace, WindowContext,
BorrowWindow, Bounds, DispatchPhase, Element, ElementId, ExternalPaths, FocusHandle, Font,
FontStyle, FontWeight, HighlightStyle, Hsla, InteractiveElement, InteractiveElementState,
Interactivity, IntoElement, LayoutId, Model, ModelContext, ModifiersChangedEvent, MouseButton,
Pixels, PlatformInputHandler, Point, Rgba, ShapedLine, Size, StatefulInteractiveElement,
Styled, TextRun, TextStyle, TextSystem, UnderlineStyle, WhiteSpace, WindowContext,
};
use itertools::Itertools;
use language::CursorShape;

View file

@ -96,6 +96,7 @@ impl RenderOnce for TabBar {
div()
.id(self.id)
.z_index(120) // todo!("z-index")
.group("tab_bar")
.flex()
.flex_none()

View file

@ -105,6 +105,7 @@ impl Render for Toolbar {
v_stack()
.p_1()
.gap_2()
.z_index(80) // todo!("z-index")
.border_b()
.border_color(cx.theme().colors().border_variant)
.bg(cx.theme().colors().toolbar_background)