mirror of
https://github.com/zed-industries/zed.git
synced 2025-01-05 23:51:08 +00:00
WIP
This commit is contained in:
parent
92bda1231e
commit
2e056e9b0b
8 changed files with 366 additions and 11 deletions
|
@ -52,6 +52,8 @@ fn generate_shader_bindings() -> PathBuf {
|
|||
"AtlasTile".into(),
|
||||
"QuadInputIndex".into(),
|
||||
"Quad".into(),
|
||||
"ShadowInputIndex".into(),
|
||||
"Shadow".into(),
|
||||
"SpriteInputIndex".into(),
|
||||
"MonochromeSprite".into(),
|
||||
"PolychromeSprite".into(),
|
||||
|
|
|
@ -469,6 +469,17 @@ impl Edges<AbsoluteLength> {
|
|||
}
|
||||
}
|
||||
|
||||
impl Edges<Pixels> {
|
||||
pub fn scale(&self, factor: f32) -> Edges<ScaledPixels> {
|
||||
Edges {
|
||||
top: self.top.scale(factor),
|
||||
right: self.right.scale(factor),
|
||||
bottom: self.bottom.scale(factor),
|
||||
left: self.left.scale(factor),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Refineable, Clone, Default, Debug, Eq, PartialEq)]
|
||||
#[refineable(debug)]
|
||||
#[repr(C)]
|
||||
|
@ -480,8 +491,8 @@ pub struct Corners<T: Clone + Debug> {
|
|||
}
|
||||
|
||||
impl Corners<AbsoluteLength> {
|
||||
pub fn to_pixels(&self, bounds: Bounds<Pixels>, rem_size: Pixels) -> Corners<Pixels> {
|
||||
let max = bounds.size.width.max(bounds.size.height) / 2.;
|
||||
pub fn to_pixels(&self, size: Size<Pixels>, rem_size: Pixels) -> Corners<Pixels> {
|
||||
let max = size.width.max(size.height) / 2.;
|
||||
Corners {
|
||||
top_left: self.top_left.to_pixels(rem_size).min(max),
|
||||
top_right: self.top_right.to_pixels(rem_size).min(max),
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::{
|
||||
point, size, AtlasTextureId, DevicePixels, MetalAtlas, MonochromeSprite, PolychromeSprite,
|
||||
Quad, Scene, Size,
|
||||
Quad, Scene, Shadow, Size,
|
||||
};
|
||||
use cocoa::{
|
||||
base::{NO, YES},
|
||||
|
@ -18,6 +18,7 @@ pub struct MetalRenderer {
|
|||
layer: metal::MetalLayer,
|
||||
command_queue: CommandQueue,
|
||||
quads_pipeline_state: metal::RenderPipelineState,
|
||||
shadows_pipeline_state: metal::RenderPipelineState,
|
||||
monochrome_sprites_pipeline_state: metal::RenderPipelineState,
|
||||
polychrome_sprites_pipeline_state: metal::RenderPipelineState,
|
||||
unit_vertices: metal::Buffer,
|
||||
|
@ -90,6 +91,14 @@ impl MetalRenderer {
|
|||
"quad_fragment",
|
||||
PIXEL_FORMAT,
|
||||
);
|
||||
let shadows_pipeline_state = build_pipeline_state(
|
||||
&device,
|
||||
&library,
|
||||
"shadows",
|
||||
"shadow_vertex",
|
||||
"shadow_fragment",
|
||||
PIXEL_FORMAT,
|
||||
);
|
||||
let monochrome_sprites_pipeline_state = build_pipeline_state(
|
||||
&device,
|
||||
&library,
|
||||
|
@ -114,6 +123,7 @@ impl MetalRenderer {
|
|||
layer,
|
||||
command_queue,
|
||||
quads_pipeline_state,
|
||||
shadows_pipeline_state,
|
||||
monochrome_sprites_pipeline_state,
|
||||
polychrome_sprites_pipeline_state,
|
||||
unit_vertices,
|
||||
|
@ -183,6 +193,14 @@ impl MetalRenderer {
|
|||
command_encoder,
|
||||
);
|
||||
}
|
||||
crate::PrimitiveBatch::Shadows(shadows) => {
|
||||
self.draw_shadows(
|
||||
shadows,
|
||||
&mut instance_offset,
|
||||
viewport_size,
|
||||
command_encoder,
|
||||
);
|
||||
}
|
||||
crate::PrimitiveBatch::MonochromeSprites {
|
||||
texture_id,
|
||||
sprites,
|
||||
|
@ -279,6 +297,66 @@ impl MetalRenderer {
|
|||
*offset = next_offset;
|
||||
}
|
||||
|
||||
fn draw_shadows(
|
||||
&mut self,
|
||||
shadows: &[Shadow],
|
||||
offset: &mut usize,
|
||||
viewport_size: Size<DevicePixels>,
|
||||
command_encoder: &metal::RenderCommandEncoderRef,
|
||||
) {
|
||||
if shadows.is_empty() {
|
||||
return;
|
||||
}
|
||||
align_offset(offset);
|
||||
|
||||
command_encoder.set_render_pipeline_state(&self.shadows_pipeline_state);
|
||||
command_encoder.set_vertex_buffer(
|
||||
ShadowInputIndex::Vertices as u64,
|
||||
Some(&self.unit_vertices),
|
||||
0,
|
||||
);
|
||||
command_encoder.set_vertex_buffer(
|
||||
ShadowInputIndex::Shadows as u64,
|
||||
Some(&self.instances),
|
||||
*offset as u64,
|
||||
);
|
||||
command_encoder.set_fragment_buffer(
|
||||
ShadowInputIndex::Shadows as u64,
|
||||
Some(&self.instances),
|
||||
*offset as u64,
|
||||
);
|
||||
|
||||
command_encoder.set_vertex_bytes(
|
||||
ShadowInputIndex::ViewportSize as u64,
|
||||
mem::size_of_val(&viewport_size) as u64,
|
||||
&viewport_size as *const Size<DevicePixels> as *const _,
|
||||
);
|
||||
|
||||
let shadow_bytes_len = mem::size_of::<Shadow>() * shadows.len();
|
||||
let buffer_contents = unsafe { (self.instances.contents() as *mut u8).add(*offset) };
|
||||
unsafe {
|
||||
ptr::copy_nonoverlapping(
|
||||
shadows.as_ptr() as *const u8,
|
||||
buffer_contents,
|
||||
shadow_bytes_len,
|
||||
);
|
||||
}
|
||||
|
||||
let next_offset = *offset + shadow_bytes_len;
|
||||
assert!(
|
||||
next_offset <= INSTANCE_BUFFER_SIZE,
|
||||
"instance buffer exhausted"
|
||||
);
|
||||
|
||||
command_encoder.draw_primitives_instanced(
|
||||
metal::MTLPrimitiveType::Triangle,
|
||||
0,
|
||||
6,
|
||||
shadows.len() as u64,
|
||||
);
|
||||
*offset = next_offset;
|
||||
}
|
||||
|
||||
fn draw_monochrome_sprites(
|
||||
&mut self,
|
||||
texture_id: AtlasTextureId,
|
||||
|
@ -469,6 +547,13 @@ enum QuadInputIndex {
|
|||
ViewportSize = 2,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
enum ShadowInputIndex {
|
||||
Vertices = 0,
|
||||
Shadows = 1,
|
||||
ViewportSize = 2,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
enum SpriteInputIndex {
|
||||
Vertices = 0,
|
||||
|
|
|
@ -11,6 +11,9 @@ float2 to_tile_position(float2 unit_vertex, AtlasTile tile,
|
|||
constant Size_DevicePixels *atlas_size);
|
||||
float quad_sdf(float2 point, Bounds_ScaledPixels bounds,
|
||||
Corners_ScaledPixels corner_radii);
|
||||
float gaussian(float x, float sigma);
|
||||
float2 erf(float2 x);
|
||||
float blur_along_x(float x, float y, float sigma, float corner, float2 half_size);
|
||||
|
||||
struct QuadVertexOutput {
|
||||
float4 position [[position]];
|
||||
|
@ -110,6 +113,91 @@ fragment float4 quad_fragment(QuadVertexOutput input [[stage_in]],
|
|||
return color * float4(1., 1., 1., saturate(0.5 - distance));
|
||||
}
|
||||
|
||||
struct ShadowVertexOutput {
|
||||
float4 position [[position]];
|
||||
float4 color [[flat]];
|
||||
uint shadow_id [[flat]];
|
||||
};
|
||||
|
||||
vertex ShadowVertexOutput shadow_vertex(
|
||||
uint unit_vertex_id [[vertex_id]],
|
||||
uint shadow_id [[instance_id]],
|
||||
constant float2 *unit_vertices [[buffer(ShadowInputIndex_Vertices)]],
|
||||
constant Shadow *shadows [[buffer(ShadowInputIndex_Shadows)]],
|
||||
constant Size_DevicePixels *viewport_size [[buffer(ShadowInputIndex_ViewportSize)]]
|
||||
) {
|
||||
float2 unit_vertex = unit_vertices[unit_vertex_id];
|
||||
Shadow shadow = shadows[shadow_id];
|
||||
|
||||
float margin = (3. * shadow.blur_radius) + shadow.spread_radius;
|
||||
// Set the bounds of the shadow and adjust its size based on the shadow's spread radius
|
||||
// to achieve the spreading effect
|
||||
Bounds_ScaledPixels bounds = shadow.bounds;
|
||||
bounds.origin.x -= margin;
|
||||
bounds.origin.y -= margin;
|
||||
bounds.size.width += 2. * margin;
|
||||
bounds.size.height += 2. * margin;
|
||||
|
||||
float4 device_position = to_device_position(unit_vertex, bounds, bounds, viewport_size);
|
||||
float4 color = hsla_to_rgba(shadow.color);
|
||||
|
||||
return ShadowVertexOutput {
|
||||
device_position,
|
||||
color,
|
||||
shadow_id,
|
||||
};
|
||||
}
|
||||
|
||||
fragment float4 shadow_fragment(
|
||||
ShadowVertexOutput input [[stage_in]],
|
||||
constant Shadow *shadows [[buffer(ShadowInputIndex_Shadows)]]
|
||||
) {
|
||||
Shadow shadow = shadows[input.shadow_id];
|
||||
|
||||
float2 origin = float2(
|
||||
shadow.bounds.origin.x - shadow.spread_radius,
|
||||
shadow.bounds.origin.y - shadow.spread_radius
|
||||
);
|
||||
float2 size = float2(
|
||||
shadow.bounds.size.width + shadow.spread_radius * 2.,
|
||||
shadow.bounds.size.height + shadow.spread_radius * 2.
|
||||
);
|
||||
float2 half_size = size / 2.;
|
||||
float2 center = origin + half_size;
|
||||
float2 point = input.position.xy - center;
|
||||
float corner_radius;
|
||||
if (point.x < 0.) {
|
||||
if (point.y < 0.) {
|
||||
corner_radius = shadow.corner_radii.top_left;
|
||||
} else {
|
||||
corner_radius = shadow.corner_radii.bottom_left;
|
||||
}
|
||||
} else {
|
||||
if (point.y < 0.) {
|
||||
corner_radius = shadow.corner_radii.top_right;
|
||||
} else {
|
||||
corner_radius = shadow.corner_radii.bottom_right;
|
||||
}
|
||||
}
|
||||
|
||||
// The signal is only non-zero in a limited range, so don't waste samples
|
||||
float low = point.y - half_size.y;
|
||||
float high = point.y + half_size.y;
|
||||
float start = clamp(-3. * shadow.blur_radius, low, high);
|
||||
float end = clamp(3. * shadow.blur_radius, low, high);
|
||||
|
||||
// Accumulate samples (we can get away with surprisingly few samples)
|
||||
float step = (end - start) / 4.;
|
||||
float y = start + step * 0.5;
|
||||
float alpha = 0.;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
alpha += blur_along_x(point.x, point.y - y, shadow.blur_radius, corner_radius, half_size) * gaussian(y, shadow.blur_radius) * step;
|
||||
y += step;
|
||||
}
|
||||
|
||||
return input.color * float4(1., 1., 1., alpha);
|
||||
}
|
||||
|
||||
struct MonochromeSpriteVertexOutput {
|
||||
float4 position [[position]];
|
||||
float2 tile_position;
|
||||
|
@ -308,3 +396,24 @@ float quad_sdf(float2 point, Bounds_ScaledPixels bounds,
|
|||
|
||||
return distance;
|
||||
}
|
||||
|
||||
// A standard gaussian function, used for weighting samples
|
||||
float gaussian(float x, float sigma) {
|
||||
return exp(-(x * x) / (2. * sigma * sigma)) / (sqrt(2. * M_PI_F) * sigma);
|
||||
}
|
||||
|
||||
// This approximates the error function, needed for the gaussian integral
|
||||
float2 erf(float2 x) {
|
||||
float2 s = sign(x);
|
||||
float2 a = abs(x);
|
||||
x = 1. + (0.278393 + (0.230389 + 0.078108 * (a * a)) * a) * a;
|
||||
x *= x;
|
||||
return s - s / (x * x);
|
||||
}
|
||||
|
||||
float blur_along_x(float x, float y, float sigma, float corner, float2 half_size) {
|
||||
float delta = min(half_size.y - corner - abs(y), 0.);
|
||||
float curved = half_size.x - corner + sqrt(max(0., corner * corner - delta * delta));
|
||||
float2 integral = 0.5 + 0.5 * erf((x + float2(-curved, curved)) * (sqrt(0.5) / sigma));
|
||||
return integral.y - integral.x;
|
||||
}
|
||||
|
|
|
@ -38,6 +38,9 @@ impl Scene {
|
|||
Primitive::Quad(quad) => {
|
||||
layer.quads.push(quad);
|
||||
}
|
||||
Primitive::Shadow(shadow) => {
|
||||
layer.shadows.push(shadow);
|
||||
}
|
||||
Primitive::MonochromeSprite(sprite) => {
|
||||
layer.monochrome_sprites.push(sprite);
|
||||
}
|
||||
|
@ -55,6 +58,7 @@ impl Scene {
|
|||
#[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>,
|
||||
}
|
||||
|
@ -68,6 +72,9 @@ impl SceneLayer {
|
|||
quads: &self.quads,
|
||||
quads_start: 0,
|
||||
quads_iter: self.quads.iter().peekable(),
|
||||
shadows: &self.shadows,
|
||||
shadows_start: 0,
|
||||
shadows_iter: self.shadows.iter().peekable(),
|
||||
monochrome_sprites: &self.monochrome_sprites,
|
||||
monochrome_sprites_start: 0,
|
||||
monochrome_sprites_iter: self.monochrome_sprites.iter().peekable(),
|
||||
|
@ -82,6 +89,9 @@ struct BatchIterator<'a> {
|
|||
quads: &'a [Quad],
|
||||
quads_start: usize,
|
||||
quads_iter: Peekable<slice::Iter<'a, Quad>>,
|
||||
shadows: &'a [Shadow],
|
||||
shadows_start: usize,
|
||||
shadows_iter: Peekable<slice::Iter<'a, Shadow>>,
|
||||
monochrome_sprites: &'a [MonochromeSprite],
|
||||
monochrome_sprites_start: usize,
|
||||
monochrome_sprites_iter: Peekable<slice::Iter<'a, MonochromeSprite>>,
|
||||
|
@ -96,6 +106,10 @@ impl<'a> Iterator for BatchIterator<'a> {
|
|||
fn next(&mut self) -> Option<Self::Item> {
|
||||
let mut kinds_and_orders = [
|
||||
(PrimitiveKind::Quad, self.quads_iter.peek().map(|q| q.order)),
|
||||
(
|
||||
PrimitiveKind::Shadow,
|
||||
self.shadows_iter.peek().map(|s| s.order),
|
||||
),
|
||||
(
|
||||
PrimitiveKind::MonochromeSprite,
|
||||
self.monochrome_sprites_iter.peek().map(|s| s.order),
|
||||
|
@ -127,6 +141,19 @@ impl<'a> Iterator for BatchIterator<'a> {
|
|||
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();
|
||||
self.shadows_start = shadows_end;
|
||||
Some(PrimitiveBatch::Shadows(
|
||||
&self.shadows[shadows_start..shadows_end],
|
||||
))
|
||||
}
|
||||
PrimitiveKind::MonochromeSprite => {
|
||||
let texture_id = self.monochrome_sprites_iter.peek().unwrap().tile.texture_id;
|
||||
let sprites_start = self.monochrome_sprites_start;
|
||||
|
@ -168,6 +195,7 @@ impl<'a> Iterator for BatchIterator<'a> {
|
|||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
pub enum PrimitiveKind {
|
||||
Quad,
|
||||
Shadow,
|
||||
MonochromeSprite,
|
||||
PolychromeSprite,
|
||||
}
|
||||
|
@ -175,12 +203,15 @@ pub enum PrimitiveKind {
|
|||
#[derive(Clone, Debug)]
|
||||
pub enum Primitive {
|
||||
Quad(Quad),
|
||||
Shadow(Shadow),
|
||||
MonochromeSprite(MonochromeSprite),
|
||||
PolychromeSprite(PolychromeSprite),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) enum PrimitiveBatch<'a> {
|
||||
Quads(&'a [Quad]),
|
||||
Shadows(&'a [Shadow]),
|
||||
MonochromeSprites {
|
||||
texture_id: AtlasTextureId,
|
||||
sprites: &'a [MonochromeSprite],
|
||||
|
@ -221,6 +252,36 @@ impl From<Quad> for Primitive {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
#[repr(C)]
|
||||
pub struct Shadow {
|
||||
pub order: u32,
|
||||
pub bounds: Bounds<ScaledPixels>,
|
||||
pub corner_radii: Corners<ScaledPixels>,
|
||||
pub content_mask: ScaledContentMask,
|
||||
pub color: Hsla,
|
||||
pub blur_radius: ScaledPixels,
|
||||
pub spread_radius: ScaledPixels,
|
||||
}
|
||||
|
||||
impl Ord for Shadow {
|
||||
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
||||
self.order.cmp(&other.order)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for Shadow {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Shadow> for Primitive {
|
||||
fn from(shadow: Shadow) -> Self {
|
||||
Primitive::Shadow(shadow)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
#[repr(C)]
|
||||
pub struct MonochromeSprite {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use crate::{
|
||||
phi, point, rems, AbsoluteLength, BorrowAppContext, BorrowWindow, Bounds, ContentMask, Corners,
|
||||
CornersRefinement, DefiniteLength, Edges, EdgesRefinement, Font, FontFeatures, FontStyle,
|
||||
FontWeight, Hsla, Length, Pixels, Point, PointRefinement, Quad, Rems, Result, RunStyle,
|
||||
FontWeight, Hsla, Length, Pixels, Point, PointRefinement, Quad, Rems, Result, RunStyle, Shadow,
|
||||
SharedString, Size, SizeRefinement, ViewContext, WindowContext,
|
||||
};
|
||||
use refineable::Refineable;
|
||||
|
@ -89,10 +89,21 @@ pub struct Style {
|
|||
#[refineable]
|
||||
pub corner_radii: Corners<AbsoluteLength>,
|
||||
|
||||
/// Box Shadow of the element
|
||||
pub box_shadow: Option<BoxShadow>,
|
||||
|
||||
/// TEXT
|
||||
pub text: TextStyleRefinement,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct BoxShadow {
|
||||
pub color: Hsla,
|
||||
pub offset: Point<Pixels>,
|
||||
pub blur_radius: Pixels,
|
||||
pub spread_radius: Pixels,
|
||||
}
|
||||
|
||||
#[derive(Refineable, Clone, Debug)]
|
||||
#[refineable(debug)]
|
||||
pub struct TextStyle {
|
||||
|
@ -233,6 +244,28 @@ impl Style {
|
|||
let rem_size = cx.rem_size();
|
||||
let scale = cx.scale_factor();
|
||||
|
||||
if let Some(shadow) = self.box_shadow.as_ref() {
|
||||
let layer_id = cx.current_layer_id();
|
||||
let content_mask = cx.content_mask();
|
||||
let mut shadow_bounds = bounds;
|
||||
shadow_bounds.origin += shadow.offset;
|
||||
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(bounds.size, rem_size)
|
||||
.scale(scale),
|
||||
color: shadow.color,
|
||||
blur_radius: shadow.blur_radius.scale(scale),
|
||||
spread_radius: shadow.spread_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();
|
||||
|
@ -247,10 +280,9 @@ impl Style {
|
|||
border_color: self.border_color.unwrap_or_default(),
|
||||
corner_radii: self
|
||||
.corner_radii
|
||||
.map(|length| length.to_pixels(rem_size).scale(scale)),
|
||||
border_widths: self
|
||||
.border_widths
|
||||
.map(|length| length.to_pixels(rem_size).scale(scale)),
|
||||
.to_pixels(bounds.size, rem_size)
|
||||
.scale(scale),
|
||||
border_widths: self.border_widths.to_pixels(rem_size).scale(scale),
|
||||
},
|
||||
);
|
||||
}
|
||||
|
@ -296,6 +328,7 @@ impl Default for Style {
|
|||
fill: None,
|
||||
border_color: None,
|
||||
corner_radii: Corners::default(),
|
||||
box_shadow: None,
|
||||
text: TextStyleRefinement::default(),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use crate::{
|
||||
self as gpui3, relative, rems, AlignItems, Display, Fill, FlexDirection, Hsla, JustifyContent,
|
||||
Length, Position, SharedString, Style, StyleRefinement, Styled, TextStyleRefinement,
|
||||
self as gpui3, hsla, point, px, relative, rems, AlignItems, BoxShadow, Display, Fill,
|
||||
FlexDirection, Hsla, JustifyContent, Length, Position, SharedString, Style, StyleRefinement,
|
||||
Styled, TextStyleRefinement,
|
||||
};
|
||||
|
||||
pub trait StyleHelpers: Styled<Style = Style> {
|
||||
|
@ -213,6 +214,58 @@ pub trait StyleHelpers: Styled<Style = Style> {
|
|||
self
|
||||
}
|
||||
|
||||
fn shadow(mut self) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self
|
||||
}
|
||||
|
||||
fn shadow_sm(mut self) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.declared_style().box_shadow = Some(BoxShadow {
|
||||
color: hsla(0., 0., 0., 1.),
|
||||
offset: point(px(0.), px(0.)),
|
||||
blur_radius: px(1.),
|
||||
spread_radius: px(0.),
|
||||
});
|
||||
self
|
||||
}
|
||||
|
||||
fn shadow_md(mut self) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
todo!();
|
||||
self
|
||||
}
|
||||
|
||||
fn shadow_lg(mut self) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
todo!();
|
||||
self
|
||||
}
|
||||
|
||||
fn shadow_xl(mut self) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
todo!();
|
||||
self
|
||||
}
|
||||
|
||||
fn shadow_2xl(mut self) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
todo!();
|
||||
self
|
||||
}
|
||||
|
||||
fn text_style(&mut self) -> &mut Option<TextStyleRefinement> {
|
||||
let style: &mut StyleRefinement = self.declared_style();
|
||||
&mut style.text
|
||||
|
|
|
@ -168,7 +168,8 @@ impl CollabPanel {
|
|||
.uri(avatar_uri)
|
||||
.size_3p5()
|
||||
.rounded_full()
|
||||
.fill(theme.middle.positive.default.foreground),
|
||||
.fill(theme.middle.positive.default.foreground)
|
||||
.shadow_sm(),
|
||||
)
|
||||
.child(label),
|
||||
)
|
||||
|
|
Loading…
Reference in a new issue