Checkpoint

This commit is contained in:
Nathan Sobo 2023-10-05 14:42:11 -06:00
parent fe3ef08f39
commit 6f7c305308
13 changed files with 1190 additions and 194 deletions

View File

@ -7,7 +7,7 @@ description = "The next version of Zed's GPU-accelerated UI framework"
publish = false
[features]
test = ["backtrace", "dhat", "env_logger", "collections/test-support"]
test = ["backtrace", "dhat", "env_logger", "collections/test-support", "util/test-support"]
[lib]
path = "src/gpui3.rs"
@ -66,6 +66,7 @@ dhat = "0.3"
env_logger.workspace = true
png = "0.16"
simplelog = "0.9"
util = { path = "../util", features = ["test-support"] }
[build-dependencies]
bindgen = "0.65.1"

View File

@ -48,17 +48,14 @@ impl<S: 'static + Send + Sync> Element for Div<S> {
let Layout { order, bounds } = layout;
let style = self.computed_style();
style.paint(order, bounds, cx);
cx.stack(0, |cx| style.paint(order, bounds, cx));
// // todo!("support only one dimension being hidden")
let overflow = &style.overflow;
// if style.overflow.y != Overflow::Visible || style.overflow.x != Overflow::Visible {
// cx.clip(layout.bounds, style.corner_radii, || )
// }
style.apply_text_style(cx, |cx| {
style.apply_overflow(layout.bounds, cx, |cx| {
self.paint_children(overflow, state, cx)
cx.stack(1, |cx| {
style.apply_overflow(layout.bounds, cx, |cx| {
self.paint_children(overflow, state, cx)
})
})
})?;
self.handle_scroll(order, bounds, style.overflow.clone(), child_layouts, cx);

View File

@ -73,7 +73,9 @@ impl<S: Send + Sync + 'static> Element for Img<S> {
.and_then(ResultExt::log_err)
{
let corner_radii = style.corner_radii.to_pixels(bounds.size, cx.rem_size());
cx.paint_image(bounds, corner_radii, order, data, self.grayscale)?;
cx.stack(1, |cx| {
cx.paint_image(bounds, corner_radii, order, data, self.grayscale)
})?;
} else {
cx.spawn(|_, mut cx| async move {
if image_future.await.log_err().is_some() {

View File

@ -2,7 +2,7 @@ use core::fmt::Debug;
use derive_more::{Add, AddAssign, Div, Mul, Sub, SubAssign};
use refineable::Refineable;
use std::{
cmp,
cmp, fmt,
ops::{Add, AddAssign, Div, Mul, MulAssign, Sub, SubAssign},
};
@ -128,7 +128,7 @@ impl<T: Clone + Debug> Clone for Point<T> {
}
}
#[derive(Refineable, Default, Clone, Copy, Debug, PartialEq, Div, Hash)]
#[derive(Refineable, Default, Clone, Copy, PartialEq, Div, Hash)]
#[refineable(debug)]
#[repr(C)]
pub struct Size<T: Clone + Debug> {
@ -199,14 +199,11 @@ impl<T: Clone + Debug + Mul<S, Output = T>, S: Clone> MulAssign<S> for Size<T> {
impl<T: Eq + Debug + Clone> Eq for Size<T> {}
// impl From<Size<Option<Pixels>>> for Size<Option<f32>> {
// fn from(size: Size<Option<Pixels>>) -> Self {
// Size {
// width: size.width.map(|p| p.0 as f32),
// height: size.height.map(|p| p.0 as f32),
// }
// }
// }
impl<T: Clone + Debug> Debug for Size<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Size {{ {:?} × {:?} }}", self.width, self.height)
}
}
impl From<Size<Pixels>> for Size<GlobalPixels> {
fn from(size: Size<Pixels>) -> Self {
@ -345,6 +342,13 @@ impl<T: Clone + Debug + Add<T, Output = T>> Bounds<T> {
y: self.origin.y.clone() + self.size.height.clone(),
}
}
pub fn lower_left(&self) -> Point<T> {
Point {
x: self.origin.x.clone(),
y: self.origin.y.clone() + self.size.height.clone(),
}
}
}
impl<T: Clone + Debug + PartialOrd + Add<T, Output = T>> Bounds<T> {
@ -627,7 +631,7 @@ impl From<f32> for Pixels {
}
impl Debug for Pixels {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{} px", self.0)
}
}
@ -662,8 +666,8 @@ impl DevicePixels {
}
}
impl std::fmt::Debug for DevicePixels {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
impl fmt::Debug for DevicePixels {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{} px (device)", self.0)
}
}
@ -721,7 +725,7 @@ impl ScaledPixels {
impl Eq for ScaledPixels {}
impl Debug for ScaledPixels {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{} px (scaled)", self.0)
}
}
@ -738,12 +742,18 @@ impl From<DevicePixels> for ScaledPixels {
}
}
impl From<ScaledPixels> for f64 {
fn from(scaled_pixels: ScaledPixels) -> Self {
scaled_pixels.0 as f64
}
}
#[derive(Clone, Copy, Default, Add, AddAssign, Sub, SubAssign, Div, PartialEq, PartialOrd)]
#[repr(transparent)]
pub struct GlobalPixels(pub(crate) f32);
impl Debug for GlobalPixels {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{} px (global coordinate space)", self.0)
}
}
@ -772,7 +782,7 @@ impl Mul<Pixels> for Rems {
}
impl Debug for Rems {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{} rem", self.0)
}
}
@ -840,7 +850,7 @@ impl DefiniteLength {
}
impl Debug for DefiniteLength {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
DefiniteLength::Absolute(length) => Debug::fmt(length, f),
DefiniteLength::Fraction(fract) => write!(f, "{}%", (fract * 100.0) as i32),
@ -880,7 +890,7 @@ pub enum Length {
}
impl Debug for Length {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Length::Definite(definite_length) => write!(f, "{:?}", definite_length),
Length::Auto => write!(f, "auto"),

View File

@ -182,49 +182,42 @@ impl MetalRenderer {
});
let mut instance_offset = 0;
for layer in scene.layers() {
for batch in layer.batches() {
match batch {
crate::PrimitiveBatch::Quads(quads) => {
self.draw_quads(
quads,
&mut instance_offset,
viewport_size,
command_encoder,
);
}
crate::PrimitiveBatch::Shadows(shadows) => {
self.draw_shadows(
shadows,
&mut instance_offset,
viewport_size,
command_encoder,
);
}
crate::PrimitiveBatch::MonochromeSprites {
for batch in scene.batches() {
match batch {
crate::PrimitiveBatch::Quads(quads) => {
self.draw_quads(quads, &mut instance_offset, viewport_size, command_encoder);
}
crate::PrimitiveBatch::Shadows(shadows) => {
self.draw_shadows(
shadows,
&mut instance_offset,
viewport_size,
command_encoder,
);
}
crate::PrimitiveBatch::MonochromeSprites {
texture_id,
sprites,
} => {
self.draw_monochrome_sprites(
texture_id,
sprites,
} => {
self.draw_monochrome_sprites(
texture_id,
sprites,
&mut instance_offset,
viewport_size,
command_encoder,
);
}
crate::PrimitiveBatch::PolychromeSprites {
&mut instance_offset,
viewport_size,
command_encoder,
);
}
crate::PrimitiveBatch::PolychromeSprites {
texture_id,
sprites,
} => {
self.draw_polychrome_sprites(
texture_id,
sprites,
} => {
self.draw_polychrome_sprites(
texture_id,
sprites,
&mut instance_offset,
viewport_size,
command_encoder,
);
}
&mut instance_offset,
viewport_size,
command_encoder,
);
}
}
}

View File

@ -1,18 +1,26 @@
use std::{iter::Peekable, mem, slice};
use super::{Bounds, Hsla, Point};
use crate::{AtlasTextureId, AtlasTile, Corners, Edges, ScaledContentMask, ScaledPixels};
use crate::{
AtlasTextureId, AtlasTile, Bounds, Corners, Edges, Hsla, Point, ScaledContentMask, ScaledPixels,
};
use collections::BTreeMap;
use etagere::euclid::{Point3D, Vector3D};
use plane_split::{BspSplitter, Polygon as BspPolygon};
use smallvec::SmallVec;
use std::{iter::Peekable, mem, slice};
// Exported to metal
pub type PointF = Point<f32>;
pub type LayerId = SmallVec<[u32; 16]>;
pub type StackingOrder = SmallVec<[u32; 16]>;
pub type LayerId = u32;
pub type DrawOrder = u32;
#[derive(Debug)]
pub struct Scene {
pub(crate) scale_factor: f32,
pub(crate) layers: BTreeMap<LayerId, SceneLayer>,
pub(crate) layers: BTreeMap<StackingOrder, LayerId>,
pub quads: Vec<Quad>,
pub shadows: Vec<Shadow>,
pub monochrome_sprites: Vec<MonochromeSprite>,
pub polychrome_sprites: Vec<PolychromeSprite>,
}
impl Scene {
@ -20,6 +28,10 @@ impl Scene {
Scene {
scale_factor,
layers: BTreeMap::new(),
quads: Vec::new(),
shadows: Vec::new(),
monochrome_sprites: Vec::new(),
polychrome_sprites: Vec::new(),
}
}
@ -27,47 +39,95 @@ impl Scene {
Scene {
scale_factor: self.scale_factor,
layers: mem::take(&mut self.layers),
quads: mem::take(&mut self.quads),
shadows: mem::take(&mut self.shadows),
monochrome_sprites: mem::take(&mut self.monochrome_sprites),
polychrome_sprites: mem::take(&mut self.polychrome_sprites),
}
}
pub fn insert(&mut self, stacking_order: LayerId, primitive: impl Into<Primitive>) {
let layer = self.layers.entry(stacking_order).or_default();
pub fn insert(&mut self, layer_id: StackingOrder, primitive: impl Into<Primitive>) {
let next_id = self.layers.len() as LayerId;
let layer_id = *self.layers.entry(layer_id).or_insert(next_id);
let primitive = primitive.into();
match primitive {
Primitive::Quad(quad) => {
layer.quads.push(quad);
Primitive::Quad(mut quad) => {
quad.order = layer_id;
self.quads.push(quad);
}
Primitive::Shadow(shadow) => {
layer.shadows.push(shadow);
Primitive::Shadow(mut shadow) => {
shadow.order = layer_id;
self.shadows.push(shadow);
}
Primitive::MonochromeSprite(sprite) => {
layer.monochrome_sprites.push(sprite);
Primitive::MonochromeSprite(mut sprite) => {
sprite.order = layer_id;
self.monochrome_sprites.push(sprite);
}
Primitive::PolychromeSprite(sprite) => {
layer.polychrome_sprites.push(sprite);
Primitive::PolychromeSprite(mut sprite) => {
sprite.order = layer_id;
self.polychrome_sprites.push(sprite);
}
}
}
pub(crate) fn layers(&mut self) -> impl Iterator<Item = &mut SceneLayer> {
self.layers.values_mut()
}
}
pub(crate) fn batches(&mut self) -> impl Iterator<Item = PrimitiveBatch> {
// Map each layer id to a float between 0. and 1., with 1. closer to the viewer.
let mut layer_z_values = vec![0.; self.layers.len()];
for (ix, layer_id) in self.layers.values().enumerate() {
layer_z_values[*layer_id as usize] = ix as f32 / self.layers.len() as f32;
}
#[derive(Debug, Default)]
pub(crate) struct SceneLayer {
pub quads: Vec<Quad>,
pub shadows: Vec<Shadow>,
pub monochrome_sprites: Vec<MonochromeSprite>,
pub polychrome_sprites: Vec<PolychromeSprite>,
}
// Add all primitives to the BSP splitter to determine draw order
let mut splitter = BspSplitter::new();
for (ix, quad) in self.quads.iter().enumerate() {
let z = layer_z_values[quad.order as LayerId as usize];
splitter.add(quad.bounds.to_bsp_polygon(z, (PrimitiveKind::Quad, ix)));
}
impl SceneLayer {
pub fn batches(&mut self) -> impl Iterator<Item = PrimitiveBatch> {
for (ix, shadow) in self.shadows.iter().enumerate() {
let z = layer_z_values[shadow.order as LayerId as usize];
splitter.add(shadow.bounds.to_bsp_polygon(z, (PrimitiveKind::Shadow, ix)));
}
for (ix, monochrome_sprite) in self.monochrome_sprites.iter().enumerate() {
let z = layer_z_values[monochrome_sprite.order as LayerId as usize];
splitter.add(
monochrome_sprite
.bounds
.to_bsp_polygon(z, (PrimitiveKind::MonochromeSprite, ix)),
);
}
for (ix, polychrome_sprite) in self.polychrome_sprites.iter().enumerate() {
let z = layer_z_values[polychrome_sprite.order as LayerId as usize];
splitter.add(
polychrome_sprite
.bounds
.to_bsp_polygon(z, (PrimitiveKind::PolychromeSprite, ix)),
);
}
// Sort all polygons, then reassign the order field of each primitive to `draw_order`
// We need primitives to be repr(C), hence the weird reuse of the order field for two different types.
for (draw_order, polygon) in splitter.sort(Vector3D::new(0., 0., 1.)).iter().enumerate() {
match polygon.anchor {
(PrimitiveKind::Quad, ix) => self.quads[ix].order = draw_order as DrawOrder,
(PrimitiveKind::Shadow, ix) => self.shadows[ix].order = draw_order as DrawOrder,
(PrimitiveKind::MonochromeSprite, ix) => {
self.monochrome_sprites[ix].order = draw_order as DrawOrder
}
(PrimitiveKind::PolychromeSprite, ix) => {
self.polychrome_sprites[ix].order = draw_order as DrawOrder
}
}
}
// Sort the primitives
self.quads.sort_unstable();
self.shadows.sort_unstable();
self.monochrome_sprites.sort_unstable();
self.polychrome_sprites.sort_unstable();
BatchIterator {
quads: &self.quads,
quads_start: 0,
@ -104,27 +164,27 @@ impl<'a> Iterator for BatchIterator<'a> {
type Item = PrimitiveBatch<'a>;
fn next(&mut self) -> Option<Self::Item> {
let mut kinds_and_orders = [
(PrimitiveKind::Quad, self.quads_iter.peek().map(|q| q.order)),
let mut orders_and_kinds = [
(self.quads_iter.peek().map(|q| q.order), PrimitiveKind::Quad),
(
PrimitiveKind::Shadow,
self.shadows_iter.peek().map(|s| s.order),
PrimitiveKind::Shadow,
),
(
PrimitiveKind::MonochromeSprite,
self.monochrome_sprites_iter.peek().map(|s| s.order),
PrimitiveKind::MonochromeSprite,
),
(
PrimitiveKind::PolychromeSprite,
self.polychrome_sprites_iter.peek().map(|s| s.order),
PrimitiveKind::PolychromeSprite,
),
];
kinds_and_orders.sort_by_key(|(_, order)| order.unwrap_or(u32::MAX));
orders_and_kinds.sort_by_key(|(order, kind)| (order.unwrap_or(u32::MAX), *kind));
let first = kinds_and_orders[0];
let second = kinds_and_orders[1];
let (batch_kind, max_order) = if first.1.is_some() {
(first.0, second.1.unwrap_or(u32::MAX))
let first = orders_and_kinds[0];
let second = orders_and_kinds[1];
let (batch_kind, max_order) = if first.0.is_some() {
(first.1, second.0.unwrap_or(u32::MAX))
} else {
return None;
};
@ -132,23 +192,27 @@ impl<'a> Iterator for BatchIterator<'a> {
match batch_kind {
PrimitiveKind::Quad => {
let quads_start = self.quads_start;
let quads_end = quads_start
+ self
.quads_iter
.by_ref()
.take_while(|quad| quad.order <= max_order)
.count();
let mut quads_end = quads_start;
while self
.quads_iter
.next_if(|quad| quad.order <= max_order)
.is_some()
{
quads_end += 1;
}
self.quads_start = quads_end;
Some(PrimitiveBatch::Quads(&self.quads[quads_start..quads_end]))
}
PrimitiveKind::Shadow => {
let shadows_start = self.shadows_start;
let shadows_end = shadows_start
+ self
.shadows_iter
.by_ref()
.take_while(|shadow| shadow.order <= max_order)
.count();
let mut shadows_end = shadows_start;
while self
.shadows_iter
.next_if(|shadow| shadow.order <= max_order)
.is_some()
{
shadows_end += 1;
}
self.shadows_start = shadows_end;
Some(PrimitiveBatch::Shadows(
&self.shadows[shadows_start..shadows_end],
@ -157,14 +221,16 @@ impl<'a> Iterator for BatchIterator<'a> {
PrimitiveKind::MonochromeSprite => {
let texture_id = self.monochrome_sprites_iter.peek().unwrap().tile.texture_id;
let sprites_start = self.monochrome_sprites_start;
let sprites_end = sprites_start
+ self
.monochrome_sprites_iter
.by_ref()
.take_while(|sprite| {
sprite.order <= max_order && sprite.tile.texture_id == texture_id
})
.count();
let mut sprites_end = sprites_start;
while self
.monochrome_sprites_iter
.next_if(|sprite| {
sprite.order <= max_order && sprite.tile.texture_id == texture_id
})
.is_some()
{
sprites_end += 1;
}
self.monochrome_sprites_start = sprites_end;
Some(PrimitiveBatch::MonochromeSprites {
texture_id,
@ -174,14 +240,16 @@ impl<'a> Iterator for BatchIterator<'a> {
PrimitiveKind::PolychromeSprite => {
let texture_id = self.polychrome_sprites_iter.peek().unwrap().tile.texture_id;
let sprites_start = self.polychrome_sprites_start;
let sprites_end = sprites_start
+ self
.polychrome_sprites_iter
.by_ref()
.take_while(|sprite| {
sprite.order <= max_order && sprite.tile.texture_id == texture_id
})
.count();
let mut sprites_end = self.polychrome_sprites_start;
while self
.polychrome_sprites_iter
.next_if(|sprite| {
sprite.order <= max_order && sprite.tile.texture_id == texture_id
})
.is_some()
{
sprites_end += 1;
}
self.polychrome_sprites_start = sprites_end;
Some(PrimitiveBatch::PolychromeSprites {
texture_id,
@ -192,10 +260,11 @@ impl<'a> Iterator for BatchIterator<'a> {
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Default)]
pub enum PrimitiveKind {
Quad,
Shadow,
#[default]
Quad,
MonochromeSprite,
PolychromeSprite,
}
@ -222,10 +291,10 @@ pub(crate) enum PrimitiveBatch<'a> {
},
}
#[derive(Debug, Clone, Eq, PartialEq)]
#[derive(Default, Debug, Clone, Eq, PartialEq)]
#[repr(C)]
pub struct Quad {
pub order: u32,
pub order: u32, // Initially a LayerId, then a DrawOrder.
pub bounds: Bounds<ScaledPixels>,
pub content_mask: ScaledContentMask,
pub background: Hsla,
@ -346,3 +415,76 @@ impl From<PolychromeSprite> for Primitive {
#[derive(Copy, Clone, Debug)]
pub struct AtlasId(pub(crate) usize);
impl Bounds<ScaledPixels> {
fn to_bsp_polygon<A: Copy>(&self, z: f32, anchor: A) -> BspPolygon<A> {
let upper_left = self.origin;
let upper_right = self.upper_right();
let lower_right = self.lower_right();
let lower_left = self.lower_left();
BspPolygon::from_points(
[
Point3D::new(upper_left.x.into(), upper_left.y.into(), z as f64),
Point3D::new(upper_right.x.into(), upper_right.y.into(), z as f64),
Point3D::new(lower_right.x.into(), lower_right.y.into(), z as f64),
Point3D::new(lower_left.x.into(), lower_left.y.into(), z as f64),
],
anchor,
)
.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 = Scene::new(1.0);
assert_eq!(scene.layers.len(), 0);
scene.insert(smallvec![1], quad());
scene.insert(smallvec![2], shadow());
scene.insert(smallvec![3], quad());
let mut batches_count = 0;
for _ in scene.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

@ -246,46 +246,50 @@ impl Style {
let scale = cx.scale_factor();
for shadow in &self.box_shadow {
let layer_id = cx.current_layer_id();
let content_mask = cx.content_mask();
let mut shadow_bounds = bounds;
shadow_bounds.origin += shadow.offset;
shadow_bounds.dilate(shadow.spread_radius);
cx.scene().insert(
layer_id,
Shadow {
order,
bounds: shadow_bounds.scale(scale),
content_mask: content_mask.scale(scale),
corner_radii: self
.corner_radii
.to_pixels(shadow_bounds.size, rem_size)
.scale(scale),
color: shadow.color,
blur_radius: shadow.blur_radius.scale(scale),
},
);
cx.stack(0, |cx| {
let layer_id = cx.current_stacking_order();
cx.scene().insert(
layer_id,
Shadow {
order: 0,
bounds: shadow_bounds.scale(scale),
content_mask: content_mask.scale(scale),
corner_radii: self
.corner_radii
.to_pixels(shadow_bounds.size, rem_size)
.scale(scale),
color: shadow.color,
blur_radius: shadow.blur_radius.scale(scale),
},
);
})
}
let background_color = self.fill.as_ref().and_then(Fill::color);
if background_color.is_some() || self.is_border_visible() {
let layer_id = cx.current_layer_id();
let content_mask = cx.content_mask();
cx.scene().insert(
layer_id,
Quad {
cx.stack(1, |cx| {
let order = cx.current_stacking_order();
cx.scene().insert(
order,
bounds: bounds.scale(scale),
content_mask: content_mask.scale(scale),
background: background_color.unwrap_or_default(),
border_color: self.border_color.unwrap_or_default(),
corner_radii: self
.corner_radii
.to_pixels(bounds.size, rem_size)
.scale(scale),
border_widths: self.border_widths.to_pixels(rem_size).scale(scale),
},
);
Quad {
order: 0,
bounds: bounds.scale(scale),
content_mask: content_mask.scale(scale),
background: background_color.unwrap_or_default(),
border_color: self.border_color.unwrap_or_default(),
corner_radii: self
.corner_radii
.to_pixels(bounds.size, rem_size)
.scale(scale),
border_widths: self.border_widths.to_pixels(rem_size).scale(scale),
},
);
});
}
}

View File

@ -263,7 +263,7 @@ pub trait StyleHelpers: Styled<Style = Style> {
{
self.declared_style().box_shadow = Some(smallvec![
BoxShadow {
color: hsla(0., 0., 0., 0.1),
color: hsla(0.5, 0., 0., 1.0),
offset: point(px(0.), px(4.)),
blur_radius: px(6.),
spread_radius: px(-1.),

View File

@ -1,11 +1,10 @@
use crate::{
image_cache::RenderImageParams, px, AnyView, AppContext, AsyncWindowContext, AvailableSpace,
BorrowAppContext, Bounds, Context, Corners, DevicePixels, DisplayId, Effect, Element, EntityId,
FontId, GlyphId, Handle, Hsla, ImageData, IsZero, LayerId, LayoutId, MainThread,
MainThreadOnly, MonochromeSprite, Pixels, PlatformAtlas, PlatformWindow, Point,
PolychromeSprite, Reference, RenderGlyphParams, RenderSvgParams, ScaledPixels, Scene,
SharedString, Size, Style, TaffyLayoutEngine, Task, WeakHandle, WindowOptions,
SUBPIXEL_VARIANTS,
FontId, GlyphId, Handle, Hsla, ImageData, IsZero, LayoutId, MainThread, MainThreadOnly,
MonochromeSprite, Pixels, PlatformAtlas, PlatformWindow, Point, PolychromeSprite, Reference,
RenderGlyphParams, RenderSvgParams, ScaledPixels, Scene, SharedString, Size, StackingOrder,
Style, TaffyLayoutEngine, Task, WeakHandle, WindowOptions, SUBPIXEL_VARIANTS,
};
use anyhow::Result;
use smallvec::SmallVec;
@ -24,7 +23,7 @@ pub struct Window {
layout_engine: TaffyLayoutEngine,
pub(crate) root_view: Option<AnyView<()>>,
mouse_position: Point<Pixels>,
current_layer_id: LayerId,
current_stacking_order: StackingOrder,
content_mask_stack: Vec<ContentMask>,
pub(crate) scene: Scene,
pub(crate) dirty: bool,
@ -73,7 +72,7 @@ impl Window {
layout_engine: TaffyLayoutEngine::new(),
root_view: None,
mouse_position,
current_layer_id: SmallVec::new(),
current_stacking_order: SmallVec::new(),
content_mask_stack: Vec::new(),
scene: Scene::new(scale_factor),
dirty: true,
@ -99,7 +98,7 @@ impl ContentMask {
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
#[derive(Default, Clone, Debug, PartialEq, Eq)]
#[repr(C)]
pub struct ScaledContentMask {
bounds: Bounds<ScaledPixels>,
@ -250,14 +249,14 @@ impl<'a, 'w> WindowContext<'a, 'w> {
}
pub fn stack<R>(&mut self, order: u32, f: impl FnOnce(&mut Self) -> R) -> R {
self.window.current_layer_id.push(order);
self.window.current_stacking_order.push(order);
let result = f(self);
self.window.current_layer_id.pop();
self.window.current_stacking_order.pop();
result
}
pub fn current_layer_id(&self) -> LayerId {
self.window.current_layer_id.clone()
pub fn current_stacking_order(&self) -> StackingOrder {
self.window.current_stacking_order.clone()
}
pub fn paint_glyph(
@ -286,7 +285,7 @@ impl<'a, 'w> WindowContext<'a, 'w> {
let raster_bounds = self.text_system().raster_bounds(&params)?;
if !raster_bounds.is_zero() {
let layer_id = self.current_layer_id();
let layer_id = self.current_stacking_order();
let tile =
self.window
.sprite_atlas
@ -336,7 +335,7 @@ impl<'a, 'w> WindowContext<'a, 'w> {
let raster_bounds = self.text_system().raster_bounds(&params)?;
if !raster_bounds.is_zero() {
let layer_id = self.current_layer_id();
let layer_id = self.current_stacking_order();
let tile =
self.window
.sprite_atlas
@ -382,7 +381,7 @@ impl<'a, 'w> WindowContext<'a, 'w> {
.map(|pixels| DevicePixels::from((pixels.0 * 2.).ceil() as i32)),
};
let layer_id = self.current_layer_id();
let layer_id = self.current_stacking_order();
let tile =
self.window
.sprite_atlas
@ -418,7 +417,7 @@ impl<'a, 'w> WindowContext<'a, 'w> {
let bounds = bounds.scale(scale_factor);
let params = RenderImageParams { image_id: data.id };
let layer_id = self.current_layer_id();
let order = self.current_stacking_order();
let tile = self
.window
.sprite_atlas
@ -429,9 +428,9 @@ impl<'a, 'w> WindowContext<'a, 'w> {
let corner_radii = corner_radii.scale(scale_factor);
self.window.scene.insert(
layer_id,
order,
PolychromeSprite {
order,
order: 0, // Used in in Scene::batches. 0 has no meaning.
bounds,
content_mask,
corner_radii,
@ -620,6 +619,13 @@ impl<'a, 'w, S: Send + Sync + 'static> ViewContext<'a, 'w, S> {
self.entities.weak_handle(self.entity_id)
}
pub fn stack<R>(&mut self, order: u32, f: impl FnOnce(&mut Self) -> R) -> R {
self.window.current_stacking_order.push(order);
let result = f(self);
self.window.current_stacking_order.pop();
result
}
pub fn on_next_frame(&mut self, f: impl FnOnce(&mut S, &mut ViewContext<S>) + Send + 'static) {
let entity = self.handle();
self.window_cx.on_next_frame(move |cx| {

View File

@ -92,7 +92,7 @@ impl CollabPanel {
),
]
})
.take(10)
.take(5)
.flatten(),
),
),
@ -168,7 +168,7 @@ impl CollabPanel {
.uri(avatar_uri)
.size_3p5()
.rounded_full()
// .fill(theme.middle.positive.default.foreground)
.fill(theme.middle.positive.default.foreground)
.shadow_md(),
)
.child(label),

View File

@ -1,3 +1,3 @@
mod rose_pine_dawn;
mod rose_pine;
pub use rose_pine_dawn::*;
pub use rose_pine::*;

View File

@ -1,7 +1,7 @@
use crate::theme::Theme;
use gpui3::serde_json::{self, json};
pub fn rose_pine_dawn() -> Theme {
pub fn rose_pine() -> Theme {
serde_json::from_value(json! {
{
"name": "Rosé Pine",
@ -843,3 +843,844 @@ pub fn rose_pine_dawn() -> Theme {
})
.unwrap()
}
pub fn rose_pine_dawn() -> Theme {
serde_json::from_value(json!({
"name": "Rosé Pine Dawn",
"is_light": true,
"ramps": {},
"lowest": {
"base": {
"default": {
"background": "#dcd8d8",
"border": "#dcd6d5",
"foreground": "#575279"
},
"hovered": {
"background": "#dcd6d5",
"border": "#dcd6d5",
"foreground": "#575279"
},
"pressed": {
"background": "#efe6df",
"border": "#dcd6d5",
"foreground": "#575279"
},
"active": {
"background": "#c1bac1",
"border": "#a9a3b0",
"foreground": "#575279"
},
"disabled": {
"background": "#dcd8d8",
"border": "#d0cccf",
"foreground": "#938fa3"
},
"inverted": {
"background": "#575279",
"border": "#faf4ed",
"foreground": "#c7c0c5"
}
},
"variant": {
"default": {
"background": "#dcd8d8",
"border": "#dcd6d5",
"foreground": "#706c8c"
},
"hovered": {
"background": "#dcd6d5",
"border": "#dcd6d5",
"foreground": "#706c8c"
},
"pressed": {
"background": "#efe6df",
"border": "#dcd6d5",
"foreground": "#706c8c"
},
"active": {
"background": "#c1bac1",
"border": "#a9a3b0",
"foreground": "#575279"
},
"disabled": {
"background": "#dcd8d8",
"border": "#d0cccf",
"foreground": "#938fa3"
},
"inverted": {
"background": "#575279",
"border": "#faf4ed",
"foreground": "#c7c0c5"
}
},
"on": {
"default": {
"background": "#fef9f2",
"border": "#e5e0df",
"foreground": "#575279"
},
"hovered": {
"background": "#e5e0df",
"border": "#e5e0df",
"foreground": "#575279"
},
"pressed": {
"background": "#d4d0d2",
"border": "#e5e0df",
"foreground": "#575279"
},
"active": {
"background": "#dbd5d4",
"border": "#dbd3d1",
"foreground": "#575279"
},
"disabled": {
"background": "#fef9f2",
"border": "#f6f1eb",
"foreground": "#b1abb5"
},
"inverted": {
"background": "#575279",
"border": "#faf4ed",
"foreground": "#d6d1d1"
}
},
"accent": {
"default": {
"background": "#dde9eb",
"border": "#c3d7db",
"foreground": "#57949f"
},
"hovered": {
"background": "#c3d7db",
"border": "#c3d7db",
"foreground": "#57949f"
},
"pressed": {
"background": "#b6cfd3",
"border": "#c3d7db",
"foreground": "#57949f"
},
"active": {
"background": "#a3c3c9",
"border": "#8db6bd",
"foreground": "#06090a"
},
"disabled": {
"background": "#dde9eb",
"border": "#d0e0e3",
"foreground": "#72a5ae"
},
"inverted": {
"background": "#06090a",
"border": "#ffffff",
"foreground": "#a8c7cd"
}
},
"positive": {
"default": {
"background": "#dbeee7",
"border": "#bee0d5",
"foreground": "#3eaa8e"
},
"hovered": {
"background": "#bee0d5",
"border": "#bee0d5",
"foreground": "#3eaa8e"
},
"pressed": {
"background": "#b0dacb",
"border": "#bee0d5",
"foreground": "#3eaa8e"
},
"active": {
"background": "#9bd0bf",
"border": "#82c6b1",
"foreground": "#060a09"
},
"disabled": {
"background": "#dbeee7",
"border": "#cde7de",
"foreground": "#63b89f"
},
"inverted": {
"background": "#060a09",
"border": "#ffffff",
"foreground": "#a1d4c3"
}
},
"warning": {
"default": {
"background": "#ffebd6",
"border": "#ffdab7",
"foreground": "#e99d35"
},
"hovered": {
"background": "#ffdab7",
"border": "#ffdab7",
"foreground": "#e99d35"
},
"pressed": {
"background": "#fed2a6",
"border": "#ffdab7",
"foreground": "#e99d35"
},
"active": {
"background": "#fbc891",
"border": "#f7bc77",
"foreground": "#330704"
},
"disabled": {
"background": "#ffebd6",
"border": "#ffe2c7",
"foreground": "#f1ac57"
},
"inverted": {
"background": "#330704",
"border": "#ffffff",
"foreground": "#fccb97"
}
},
"negative": {
"default": {
"background": "#f1dfe3",
"border": "#e6c6cd",
"foreground": "#b4647a"
},
"hovered": {
"background": "#e6c6cd",
"border": "#e6c6cd",
"foreground": "#b4647a"
},
"pressed": {
"background": "#e0bac2",
"border": "#e6c6cd",
"foreground": "#b4647a"
},
"active": {
"background": "#d8a8b3",
"border": "#ce94a3",
"foreground": "#0b0708"
},
"disabled": {
"background": "#f1dfe3",
"border": "#ecd2d8",
"foreground": "#c17b8e"
},
"inverted": {
"background": "#0b0708",
"border": "#ffffff",
"foreground": "#dbadb8"
}
}
},
"middle": {
"base": {
"default": {
"background": "#fef9f2",
"border": "#e5e0df",
"foreground": "#575279"
},
"hovered": {
"background": "#e5e0df",
"border": "#e5e0df",
"foreground": "#575279"
},
"pressed": {
"background": "#d4d0d2",
"border": "#e5e0df",
"foreground": "#575279"
},
"active": {
"background": "#dbd5d4",
"border": "#dbd3d1",
"foreground": "#575279"
},
"disabled": {
"background": "#fef9f2",
"border": "#f6f1eb",
"foreground": "#b1abb5"
},
"inverted": {
"background": "#575279",
"border": "#faf4ed",
"foreground": "#d6d1d1"
}
},
"variant": {
"default": {
"background": "#fef9f2",
"border": "#e5e0df",
"foreground": "#706c8c"
},
"hovered": {
"background": "#e5e0df",
"border": "#e5e0df",
"foreground": "#706c8c"
},
"pressed": {
"background": "#d4d0d2",
"border": "#e5e0df",
"foreground": "#706c8c"
},
"active": {
"background": "#dbd5d4",
"border": "#dbd3d1",
"foreground": "#575279"
},
"disabled": {
"background": "#fef9f2",
"border": "#f6f1eb",
"foreground": "#b1abb5"
},
"inverted": {
"background": "#575279",
"border": "#faf4ed",
"foreground": "#d6d1d1"
}
},
"on": {
"default": {
"background": "#faf4ed",
"border": "#fdf8f1",
"foreground": "#575279"
},
"hovered": {
"background": "#fdf8f1",
"border": "#fdf8f1",
"foreground": "#575279"
},
"pressed": {
"background": "#fdf8f2",
"border": "#fdf8f1",
"foreground": "#575279"
},
"active": {
"background": "#e6e1e0",
"border": "#d0cccf",
"foreground": "#575279"
},
"disabled": {
"background": "#faf4ed",
"border": "#fcf6ef",
"foreground": "#efe6df"
},
"inverted": {
"background": "#575279",
"border": "#faf4ed",
"foreground": "#ede9e5"
}
},
"accent": {
"default": {
"background": "#dde9eb",
"border": "#c3d7db",
"foreground": "#57949f"
},
"hovered": {
"background": "#c3d7db",
"border": "#c3d7db",
"foreground": "#57949f"
},
"pressed": {
"background": "#b6cfd3",
"border": "#c3d7db",
"foreground": "#57949f"
},
"active": {
"background": "#a3c3c9",
"border": "#8db6bd",
"foreground": "#06090a"
},
"disabled": {
"background": "#dde9eb",
"border": "#d0e0e3",
"foreground": "#72a5ae"
},
"inverted": {
"background": "#06090a",
"border": "#ffffff",
"foreground": "#a8c7cd"
}
},
"positive": {
"default": {
"background": "#dbeee7",
"border": "#bee0d5",
"foreground": "#3eaa8e"
},
"hovered": {
"background": "#bee0d5",
"border": "#bee0d5",
"foreground": "#3eaa8e"
},
"pressed": {
"background": "#b0dacb",
"border": "#bee0d5",
"foreground": "#3eaa8e"
},
"active": {
"background": "#9bd0bf",
"border": "#82c6b1",
"foreground": "#060a09"
},
"disabled": {
"background": "#dbeee7",
"border": "#cde7de",
"foreground": "#63b89f"
},
"inverted": {
"background": "#060a09",
"border": "#ffffff",
"foreground": "#a1d4c3"
}
},
"warning": {
"default": {
"background": "#ffebd6",
"border": "#ffdab7",
"foreground": "#e99d35"
},
"hovered": {
"background": "#ffdab7",
"border": "#ffdab7",
"foreground": "#e99d35"
},
"pressed": {
"background": "#fed2a6",
"border": "#ffdab7",
"foreground": "#e99d35"
},
"active": {
"background": "#fbc891",
"border": "#f7bc77",
"foreground": "#330704"
},
"disabled": {
"background": "#ffebd6",
"border": "#ffe2c7",
"foreground": "#f1ac57"
},
"inverted": {
"background": "#330704",
"border": "#ffffff",
"foreground": "#fccb97"
}
},
"negative": {
"default": {
"background": "#f1dfe3",
"border": "#e6c6cd",
"foreground": "#b4647a"
},
"hovered": {
"background": "#e6c6cd",
"border": "#e6c6cd",
"foreground": "#b4647a"
},
"pressed": {
"background": "#e0bac2",
"border": "#e6c6cd",
"foreground": "#b4647a"
},
"active": {
"background": "#d8a8b3",
"border": "#ce94a3",
"foreground": "#0b0708"
},
"disabled": {
"background": "#f1dfe3",
"border": "#ecd2d8",
"foreground": "#c17b8e"
},
"inverted": {
"background": "#0b0708",
"border": "#ffffff",
"foreground": "#dbadb8"
}
}
},
"highest": {
"base": {
"default": {
"background": "#faf4ed",
"border": "#fdf8f1",
"foreground": "#575279"
},
"hovered": {
"background": "#fdf8f1",
"border": "#fdf8f1",
"foreground": "#575279"
},
"pressed": {
"background": "#fdf8f2",
"border": "#fdf8f1",
"foreground": "#575279"
},
"active": {
"background": "#e6e1e0",
"border": "#d0cccf",
"foreground": "#575279"
},
"disabled": {
"background": "#faf4ed",
"border": "#fcf6ef",
"foreground": "#efe6df"
},
"inverted": {
"background": "#575279",
"border": "#faf4ed",
"foreground": "#ede9e5"
}
},
"variant": {
"default": {
"background": "#faf4ed",
"border": "#fdf8f1",
"foreground": "#706c8c"
},
"hovered": {
"background": "#fdf8f1",
"border": "#fdf8f1",
"foreground": "#706c8c"
},
"pressed": {
"background": "#fdf8f2",
"border": "#fdf8f1",
"foreground": "#706c8c"
},
"active": {
"background": "#e6e1e0",
"border": "#d0cccf",
"foreground": "#575279"
},
"disabled": {
"background": "#faf4ed",
"border": "#fcf6ef",
"foreground": "#efe6df"
},
"inverted": {
"background": "#575279",
"border": "#faf4ed",
"foreground": "#ede9e5"
}
},
"on": {
"default": {
"background": "#fef9f2",
"border": "#e5e0df",
"foreground": "#575279"
},
"hovered": {
"background": "#e5e0df",
"border": "#e5e0df",
"foreground": "#575279"
},
"pressed": {
"background": "#d4d0d2",
"border": "#e5e0df",
"foreground": "#575279"
},
"active": {
"background": "#dbd5d4",
"border": "#dbd3d1",
"foreground": "#575279"
},
"disabled": {
"background": "#fef9f2",
"border": "#f6f1eb",
"foreground": "#b1abb5"
},
"inverted": {
"background": "#575279",
"border": "#faf4ed",
"foreground": "#d6d1d1"
}
},
"accent": {
"default": {
"background": "#dde9eb",
"border": "#c3d7db",
"foreground": "#57949f"
},
"hovered": {
"background": "#c3d7db",
"border": "#c3d7db",
"foreground": "#57949f"
},
"pressed": {
"background": "#b6cfd3",
"border": "#c3d7db",
"foreground": "#57949f"
},
"active": {
"background": "#a3c3c9",
"border": "#8db6bd",
"foreground": "#06090a"
},
"disabled": {
"background": "#dde9eb",
"border": "#d0e0e3",
"foreground": "#72a5ae"
},
"inverted": {
"background": "#06090a",
"border": "#ffffff",
"foreground": "#a8c7cd"
}
},
"positive": {
"default": {
"background": "#dbeee7",
"border": "#bee0d5",
"foreground": "#3eaa8e"
},
"hovered": {
"background": "#bee0d5",
"border": "#bee0d5",
"foreground": "#3eaa8e"
},
"pressed": {
"background": "#b0dacb",
"border": "#bee0d5",
"foreground": "#3eaa8e"
},
"active": {
"background": "#9bd0bf",
"border": "#82c6b1",
"foreground": "#060a09"
},
"disabled": {
"background": "#dbeee7",
"border": "#cde7de",
"foreground": "#63b89f"
},
"inverted": {
"background": "#060a09",
"border": "#ffffff",
"foreground": "#a1d4c3"
}
},
"warning": {
"default": {
"background": "#ffebd6",
"border": "#ffdab7",
"foreground": "#e99d35"
},
"hovered": {
"background": "#ffdab7",
"border": "#ffdab7",
"foreground": "#e99d35"
},
"pressed": {
"background": "#fed2a6",
"border": "#ffdab7",
"foreground": "#e99d35"
},
"active": {
"background": "#fbc891",
"border": "#f7bc77",
"foreground": "#330704"
},
"disabled": {
"background": "#ffebd6",
"border": "#ffe2c7",
"foreground": "#f1ac57"
},
"inverted": {
"background": "#330704",
"border": "#ffffff",
"foreground": "#fccb97"
}
},
"negative": {
"default": {
"background": "#f1dfe3",
"border": "#e6c6cd",
"foreground": "#b4647a"
},
"hovered": {
"background": "#e6c6cd",
"border": "#e6c6cd",
"foreground": "#b4647a"
},
"pressed": {
"background": "#e0bac2",
"border": "#e6c6cd",
"foreground": "#b4647a"
},
"active": {
"background": "#d8a8b3",
"border": "#ce94a3",
"foreground": "#0b0708"
},
"disabled": {
"background": "#f1dfe3",
"border": "#ecd2d8",
"foreground": "#c17b8e"
},
"inverted": {
"background": "#0b0708",
"border": "#ffffff",
"foreground": "#dbadb8"
}
}
},
"popover_shadow": {
"blur": 4,
"color": "#2c2a4d33",
"offset": [
1,
2
]
},
"modal_shadow": {
"blur": 16,
"color": "#2c2a4d33",
"offset": [
0,
2
]
},
"players": {
"0": {
"selection": "#57949f3d",
"cursor": "#57949f"
},
"1": {
"selection": "#3eaa8e3d",
"cursor": "#3eaa8e"
},
"2": {
"selection": "#7c697f3d",
"cursor": "#7c697f"
},
"3": {
"selection": "#907aa93d",
"cursor": "#907aa9"
},
"4": {
"selection": "#907aa93d",
"cursor": "#907aa9"
},
"5": {
"selection": "#2a69833d",
"cursor": "#2a6983"
},
"6": {
"selection": "#b4647a3d",
"cursor": "#b4647a"
},
"7": {
"selection": "#e99d353d",
"cursor": "#e99d35"
}
},
"syntax": {
"comment": {
"color": "#9893a5"
},
"operator": {
"color": "#286983"
},
"punctuation": {
"color": "#797593"
},
"variable": {
"color": "#575279"
},
"string": {
"color": "#ea9d34"
},
"type": {
"color": "#56949f"
},
"type.builtin": {
"color": "#56949f"
},
"boolean": {
"color": "#d7827e"
},
"function": {
"color": "#d7827e"
},
"keyword": {
"color": "#286983"
},
"tag": {
"color": "#56949f"
},
"function.method": {
"color": "#d7827e"
},
"title": {
"color": "#ea9d34"
},
"link_text": {
"color": "#56949f",
"italic": false
},
"link_uri": {
"color": "#d7827e"
}
},
"color_family": {
"neutral": {
"low": 39.80392156862745,
"high": 95.49019607843137,
"range": 55.686274509803916,
"scaling_value": 1.7957746478873242
},
"red": {
"low": 0,
"high": 100,
"range": 100,
"scaling_value": 1
},
"orange": {
"low": 0,
"high": 100,
"range": 100,
"scaling_value": 1
},
"yellow": {
"low": 8.823529411764707,
"high": 100,
"range": 91.17647058823529,
"scaling_value": 1.0967741935483872
},
"green": {
"low": 0,
"high": 100,
"range": 100,
"scaling_value": 1
},
"cyan": {
"low": 0,
"high": 100,
"range": 100,
"scaling_value": 1
},
"blue": {
"low": 0,
"high": 100,
"range": 100,
"scaling_value": 1
},
"violet": {
"low": 0,
"high": 100,
"range": 100,
"scaling_value": 1
},
"magenta": {
"low": 0,
"high": 100,
"range": 100,
"scaling_value": 1
}
}
}))
.unwrap()
}

View File

@ -26,8 +26,8 @@ impl Workspace {
}
fn render(&mut self, cx: &mut ViewContext<Self>) -> impl Element<State = Self> {
let theme = rose_pine_dawn();
themed(rose_pine_dawn(), cx, |cx| {
let theme = theme(cx);
div()
.size_full()
.flex()