Checkpoint

Nathan Sobo created

Change summary

crates/editor/src/element.rs             |  30 ++--
crates/gpui/src/elements/container.rs    | 163 +++++++++++++++++++++++++
crates/gpui/src/elements/image.rs        |   6 
crates/gpui/src/geometry.rs              |  66 ++++++++-
crates/gpui/src/platform/mac/renderer.rs |  18 +-
crates/gpui/src/scene.rs                 | 148 ----------------------
crates/gpui2/src/style.rs                |  37 +++++
crates/theme/src/theme.rs                |   4 
crates/workspace/src/pane_group.rs       |   2 
9 files changed, 280 insertions(+), 194 deletions(-)

Detailed changes

crates/editor/src/element.rs 🔗

@@ -32,8 +32,8 @@ use gpui::{
     json::{self, ToJson},
     platform::{CursorStyle, Modifiers, MouseButton, MouseButtonEvent, MouseMovedEvent},
     text_layout::{self, Line, RunStyle, TextLayoutCache},
-    AnyElement, Axis, Border, CursorRegion, Element, EventContext, FontCache, LayoutContext,
-    MouseRegion, PaintContext, Quad, SceneBuilder, SizeConstraint, ViewContext, WindowContext,
+    AnyElement, Axis, CursorRegion, Element, EventContext, FontCache, LayoutContext, MouseRegion,
+    PaintContext, Quad, SceneBuilder, SizeConstraint, ViewContext, WindowContext,
 };
 use itertools::Itertools;
 use json::json;
@@ -539,13 +539,13 @@ impl EditorElement {
         scene.push_quad(Quad {
             bounds: gutter_bounds,
             background: Some(self.style.gutter_background),
-            border: Border::new(0., Color::transparent_black()),
+            border: Border::new(0., Color::transparent_black()).into(),
             corner_radii: Default::default(),
         });
         scene.push_quad(Quad {
             bounds: text_bounds,
             background: Some(self.style.background),
-            border: Border::new(0., Color::transparent_black()),
+            border: Border::new(0., Color::transparent_black()).into(),
             corner_radii: Default::default(),
         });
 
@@ -573,7 +573,7 @@ impl EditorElement {
                     scene.push_quad(Quad {
                         bounds: RectF::new(origin, size),
                         background: Some(self.style.active_line_background),
-                        border: Border::default(),
+                        border: Border::default().into(),
                         corner_radii: Default::default(),
                     });
                 }
@@ -593,7 +593,7 @@ impl EditorElement {
                 scene.push_quad(Quad {
                     bounds: RectF::new(origin, size),
                     background: Some(self.style.highlighted_line_background),
-                    border: Border::default(),
+                    border: Border::default().into(),
                     corner_radii: Default::default(),
                 });
             }
@@ -623,7 +623,7 @@ impl EditorElement {
                         vec2f(1., text_bounds.height()),
                     ),
                     background: Some(color),
-                    border: Border::new(0., Color::transparent_black()),
+                    border: Border::new(0., Color::transparent_black()).into(),
                     corner_radii: Default::default(),
                 });
             }
@@ -724,7 +724,7 @@ impl EditorElement {
                     scene.push_quad(Quad {
                         bounds: highlight_bounds,
                         background: Some(diff_style.modified),
-                        border: Border::new(0., Color::transparent_black()),
+                        border: Border::new(0., Color::transparent_black()).into(),
                         corner_radii: (1. * line_height).into(),
                     });
 
@@ -757,7 +757,7 @@ impl EditorElement {
                     scene.push_quad(Quad {
                         bounds: highlight_bounds,
                         background: Some(diff_style.deleted),
-                        border: Border::new(0., Color::transparent_black()),
+                        border: Border::new(0., Color::transparent_black()).into(),
                         corner_radii: (1. * line_height).into(),
                     });
 
@@ -779,7 +779,7 @@ impl EditorElement {
             scene.push_quad(Quad {
                 bounds: highlight_bounds,
                 background: Some(color),
-                border: Border::new(0., Color::transparent_black()),
+                border: Border::new(0., Color::transparent_black()).into(),
                 corner_radii: (diff_style.corner_radius * line_height).into(),
             });
         }
@@ -1149,7 +1149,7 @@ impl EditorElement {
         if layout.show_scrollbars {
             scene.push_quad(Quad {
                 bounds: track_bounds,
-                border: style.track.border,
+                border: style.track.border.into(),
                 background: style.track.background_color,
                 ..Default::default()
             });
@@ -1180,7 +1180,7 @@ impl EditorElement {
                     scene.push_quad(Quad {
                         bounds,
                         background: Some(color),
-                        border,
+                        border: border.into(),
                         corner_radii: style.thumb.corner_radii.into(),
                     })
                 };
@@ -1240,7 +1240,7 @@ impl EditorElement {
                     scene.push_quad(Quad {
                         bounds,
                         background: Some(color),
-                        border,
+                        border: border.into(),
                         corner_radii: style.thumb.corner_radii.into(),
                     })
                 }
@@ -1248,7 +1248,7 @@ impl EditorElement {
 
             scene.push_quad(Quad {
                 bounds: thumb_bounds,
-                border: style.thumb.border,
+                border: style.thumb.border.into(),
                 background: style.thumb.background_color,
                 corner_radii: style.thumb.corner_radii.into(),
             });
@@ -2891,7 +2891,7 @@ impl Cursor {
             scene.push_quad(Quad {
                 bounds,
                 background: None,
-                border: Border::all(1., self.color),
+                border: Border::all(1., self.color).into(),
                 corner_radii: Default::default(),
             });
         } else {

crates/gpui/src/elements/container.rs 🔗

@@ -9,7 +9,7 @@ use crate::{
     },
     json::ToJson,
     platform::CursorStyle,
-    scene::{self, Border, CornerRadii, CursorRegion, Quad},
+    scene::{self, CornerRadii, CursorRegion, Quad},
     AnyElement, Element, LayoutContext, PaintContext, SceneBuilder, SizeConstraint, ViewContext,
 };
 use schemars::JsonSchema;
@@ -206,6 +206,163 @@ impl<V> Container<V> {
     }
 }
 
+#[derive(Copy, Clone, Debug, Default, JsonSchema)]
+pub struct Border {
+    pub color: Color,
+    pub width: f32,
+    pub overlay: bool,
+    pub top: bool,
+    pub bottom: bool,
+    pub left: bool,
+    pub right: bool,
+}
+
+impl Into<scene::Border> for Border {
+    fn into(self) -> scene::Border {
+        scene::Border {
+            color: self.color,
+            left: if self.left { self.width } else { 0.0 },
+            right: if self.right { self.width } else { 0.0 },
+            top: if self.top { self.width } else { 0.0 },
+            bottom: if self.bottom { self.width } else { 0.0 },
+        }
+    }
+}
+
+impl Border {
+    pub fn new(width: f32, color: Color) -> Self {
+        Self {
+            width,
+            color,
+            overlay: false,
+            top: false,
+            left: false,
+            bottom: false,
+            right: false,
+        }
+    }
+
+    pub fn all(width: f32, color: Color) -> Self {
+        Self {
+            width,
+            color,
+            overlay: false,
+            top: true,
+            left: true,
+            bottom: true,
+            right: true,
+        }
+    }
+
+    pub fn top(width: f32, color: Color) -> Self {
+        let mut border = Self::new(width, color);
+        border.top = true;
+        border
+    }
+
+    pub fn left(width: f32, color: Color) -> Self {
+        let mut border = Self::new(width, color);
+        border.left = true;
+        border
+    }
+
+    pub fn bottom(width: f32, color: Color) -> Self {
+        let mut border = Self::new(width, color);
+        border.bottom = true;
+        border
+    }
+
+    pub fn right(width: f32, color: Color) -> Self {
+        let mut border = Self::new(width, color);
+        border.right = true;
+        border
+    }
+
+    pub fn with_sides(mut self, top: bool, left: bool, bottom: bool, right: bool) -> Self {
+        self.top = top;
+        self.left = left;
+        self.bottom = bottom;
+        self.right = right;
+        self
+    }
+
+    pub fn top_width(&self) -> f32 {
+        if self.top {
+            self.width
+        } else {
+            0.0
+        }
+    }
+
+    pub fn left_width(&self) -> f32 {
+        if self.left {
+            self.width
+        } else {
+            0.0
+        }
+    }
+}
+
+impl<'de> Deserialize<'de> for Border {
+    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+    where
+        D: serde::Deserializer<'de>,
+    {
+        #[derive(Deserialize)]
+        struct BorderData {
+            pub width: f32,
+            pub color: Color,
+            #[serde(default)]
+            pub overlay: bool,
+            #[serde(default)]
+            pub top: bool,
+            #[serde(default)]
+            pub right: bool,
+            #[serde(default)]
+            pub bottom: bool,
+            #[serde(default)]
+            pub left: bool,
+        }
+
+        let data = BorderData::deserialize(deserializer)?;
+        let mut border = Border {
+            width: data.width,
+            color: data.color,
+            overlay: data.overlay,
+            top: data.top,
+            bottom: data.bottom,
+            left: data.left,
+            right: data.right,
+        };
+        if !border.top && !border.bottom && !border.left && !border.right {
+            border.top = true;
+            border.bottom = true;
+            border.left = true;
+            border.right = true;
+        }
+        Ok(border)
+    }
+}
+
+impl ToJson for Border {
+    fn to_json(&self) -> serde_json::Value {
+        let mut value = json!({});
+        if self.top {
+            value["top"] = json!(self.width);
+        }
+        if self.right {
+            value["right"] = json!(self.width);
+        }
+        if self.bottom {
+            value["bottom"] = json!(self.width);
+        }
+        if self.left {
+            value["left"] = json!(self.width);
+        }
+        value
+    }
+}
+
 impl<V: 'static> Element<V> for Container<V> {
     type LayoutState = ();
     type PaintState = ();
@@ -278,7 +435,7 @@ impl<V: 'static> Element<V> for Container<V> {
             scene.push_quad(Quad {
                 bounds: quad_bounds,
                 background: self.style.overlay_color,
-                border: self.style.border,
+                border: self.style.border.into(),
                 corner_radii: self.style.corner_radii.into(),
             });
             scene.pop_layer();
@@ -286,7 +443,7 @@ impl<V: 'static> Element<V> for Container<V> {
             scene.push_quad(Quad {
                 bounds: quad_bounds,
                 background: self.style.background_color,
-                border: self.style.border,
+                border: self.style.border.into(),
                 corner_radii: self.style.corner_radii.into(),
             });
 

crates/gpui/src/elements/image.rs 🔗

@@ -1,11 +1,11 @@
-use super::constrain_size_preserving_aspect_ratio;
+use super::{constrain_size_preserving_aspect_ratio, Border};
 use crate::{
     geometry::{
         rect::RectF,
         vector::{vec2f, Vector2F},
     },
     json::{json, ToJson},
-    scene, Border, Element, ImageData, LayoutContext, PaintContext, SceneBuilder, SizeConstraint,
+    scene, Element, ImageData, LayoutContext, PaintContext, SceneBuilder, SizeConstraint,
     ViewContext,
 };
 use schemars::JsonSchema;
@@ -102,7 +102,7 @@ impl<V: 'static> Element<V> for Image {
         if let Some(data) = layout {
             scene.push_image(scene::Image {
                 bounds,
-                border: self.style.border,
+                border: self.style.border.into(),
                 corner_radii: self.style.corner_radius.into(),
                 grayscale: self.style.grayscale,
                 data: data.clone(),

crates/gpui/src/geometry.rs 🔗

@@ -230,7 +230,16 @@ pub struct Edges<T: Clone + Default> {
     pub left: T,
 }
 
-impl Edges<DefiniteLength> {
+impl Edges<Length> {
+    pub fn auto() -> Self {
+        Self {
+            top: Length::Auto,
+            right: Length::Auto,
+            bottom: Length::Auto,
+            left: Length::Auto,
+        }
+    }
+
     pub fn zero() -> Self {
         Self {
             top: pixels(0.),
@@ -240,7 +249,10 @@ impl Edges<DefiniteLength> {
         }
     }
 
-    pub fn to_taffy(&self, rem_size: f32) -> taffy::geometry::Rect<taffy::style::LengthPercentage> {
+    pub fn to_taffy(
+        &self,
+        rem_size: f32,
+    ) -> taffy::geometry::Rect<taffy::style::LengthPercentageAuto> {
         taffy::geometry::Rect {
             top: self.top.to_taffy(rem_size),
             right: self.right.to_taffy(rem_size),
@@ -250,16 +262,27 @@ impl Edges<DefiniteLength> {
     }
 }
 
-impl Edges<Length> {
-    pub fn auto() -> Self {
+impl Edges<DefiniteLength> {
+    pub fn zero() -> Self {
         Self {
-            top: Length::Auto,
-            right: Length::Auto,
-            bottom: Length::Auto,
-            left: Length::Auto,
+            top: pixels(0.),
+            right: pixels(0.),
+            bottom: pixels(0.),
+            left: pixels(0.),
         }
     }
 
+    pub fn to_taffy(&self, rem_size: f32) -> taffy::geometry::Rect<taffy::style::LengthPercentage> {
+        taffy::geometry::Rect {
+            top: self.top.to_taffy(rem_size),
+            right: self.right.to_taffy(rem_size),
+            bottom: self.bottom.to_taffy(rem_size),
+            left: self.left.to_taffy(rem_size),
+        }
+    }
+}
+
+impl Edges<AbsoluteLength> {
     pub fn zero() -> Self {
         Self {
             top: pixels(0.),
@@ -269,10 +292,7 @@ impl Edges<Length> {
         }
     }
 
-    pub fn to_taffy(
-        &self,
-        rem_size: f32,
-    ) -> taffy::geometry::Rect<taffy::style::LengthPercentageAuto> {
+    pub fn to_taffy(&self, rem_size: f32) -> taffy::geometry::Rect<taffy::style::LengthPercentage> {
         taffy::geometry::Rect {
             top: self.top.to_taffy(rem_size),
             right: self.right.to_taffy(rem_size),
@@ -280,6 +300,21 @@ impl Edges<Length> {
             left: self.left.to_taffy(rem_size),
         }
     }
+
+    pub fn to_pixels(&self, rem_size: f32) -> Edges<f32> {
+        Edges {
+            top: self.top.to_pixels(rem_size),
+            right: self.right.to_pixels(rem_size),
+            bottom: self.bottom.to_pixels(rem_size),
+            left: self.left.to_pixels(rem_size),
+        }
+    }
+}
+
+impl Edges<f32> {
+    pub fn is_empty(&self) -> bool {
+        self.top == 0.0 && self.right == 0.0 && self.bottom == 0.0 && self.left == 0.0
+    }
 }
 
 #[derive(Clone, Copy)]
@@ -295,6 +330,13 @@ impl AbsoluteLength {
             AbsoluteLength::Rems(rems) => rems * rem_size,
         }
     }
+
+    pub fn to_taffy(&self, rem_size: f32) -> taffy::style::LengthPercentage {
+        match self {
+            AbsoluteLength::Pixels(pixels) => taffy::style::LengthPercentage::Length(*pixels),
+            AbsoluteLength::Rems(rems) => taffy::style::LengthPercentage::Length(rems * rem_size),
+        }
+    }
 }
 
 impl Default for AbsoluteLength {

crates/gpui/src/platform/mac/renderer.rs 🔗

@@ -577,7 +577,6 @@ impl Renderer {
         };
         for (ix, quad) in quads.iter().enumerate() {
             let bounds = quad.bounds * scale_factor;
-            let border_width = quad.border.width * scale_factor;
             let shader_quad = shaders::GPUIQuad {
                 origin: bounds.origin().round().to_float2(),
                 size: bounds.size().round().to_float2(),
@@ -585,10 +584,10 @@ impl Renderer {
                     .background
                     .unwrap_or_else(Color::transparent_black)
                     .to_uchar4(),
-                border_top: border_width * (quad.border.top as usize as f32),
-                border_right: border_width * (quad.border.right as usize as f32),
-                border_bottom: border_width * (quad.border.bottom as usize as f32),
-                border_left: border_width * (quad.border.left as usize as f32),
+                border_top: quad.border.top * scale_factor,
+                border_right: quad.border.right * scale_factor,
+                border_bottom: quad.border.bottom * scale_factor,
+                border_left: quad.border.left * scale_factor,
                 border_color: quad.border.color.to_uchar4(),
                 corner_radius_top_left: quad.corner_radii.top_left * scale_factor,
                 corner_radius_top_right: quad.corner_radii.top_right * scale_factor,
@@ -746,7 +745,6 @@ impl Renderer {
             let origin = image.bounds.origin() * scale_factor;
             let target_size = image.bounds.size() * scale_factor;
             let corner_radii = image.corner_radii * scale_factor;
-            let border_width = image.border.width * scale_factor;
             let (alloc_id, atlas_bounds) = self.image_cache.render(&image.data);
             images_by_atlas
                 .entry(alloc_id.atlas_id)
@@ -756,10 +754,10 @@ impl Renderer {
                     target_size: target_size.to_float2(),
                     source_size: atlas_bounds.size().to_float2(),
                     atlas_origin: atlas_bounds.origin().to_float2(),
-                    border_top: border_width * (image.border.top as usize as f32),
-                    border_right: border_width * (image.border.right as usize as f32),
-                    border_bottom: border_width * (image.border.bottom as usize as f32),
-                    border_left: border_width * (image.border.left as usize as f32),
+                    border_top: image.border.top * scale_factor,
+                    border_right: image.border.right * scale_factor,
+                    border_bottom: image.border.bottom * scale_factor,
+                    border_left: image.border.left * scale_factor,
                     border_color: image.border.color.to_uchar4(),
                     corner_radius_top_left: corner_radii.top_left,
                     corner_radius_top_right: corner_radii.top_right,

crates/gpui/src/scene.rs 🔗

@@ -8,7 +8,6 @@ use derive_more::Mul;
 use schemars::JsonSchema;
 use serde::Deserialize;
 use serde_derive::Serialize;
-use serde_json::json;
 use std::{
     any::{Any, TypeId},
     borrow::Cow,
@@ -20,7 +19,6 @@ use crate::{
     color::Color,
     fonts::{FontId, GlyphId},
     geometry::{rect::RectF, vector::Vector2F},
-    json::ToJson,
     platform::{current::Surface, CursorStyle},
     ImageData, WindowContext,
 };
@@ -171,15 +169,13 @@ pub struct Icon {
     pub color: Color,
 }
 
-#[derive(Clone, Copy, Default, Debug, JsonSchema)]
+#[derive(Clone, Copy, Default, Debug)]
 pub struct Border {
-    pub width: f32,
     pub color: Color,
-    pub overlay: bool,
-    pub top: bool,
-    pub right: bool,
-    pub bottom: bool,
-    pub left: bool,
+    pub top: f32,
+    pub right: f32,
+    pub bottom: f32,
+    pub left: f32,
 }
 
 #[derive(Clone, Copy, Default, Debug)]
@@ -191,47 +187,6 @@ pub struct Underline {
     pub squiggly: bool,
 }
 
-impl<'de> Deserialize<'de> for Border {
-    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
-    where
-        D: serde::Deserializer<'de>,
-    {
-        #[derive(Deserialize)]
-        struct BorderData {
-            pub width: f32,
-            pub color: Color,
-            #[serde(default)]
-            pub overlay: bool,
-            #[serde(default)]
-            pub top: bool,
-            #[serde(default)]
-            pub right: bool,
-            #[serde(default)]
-            pub bottom: bool,
-            #[serde(default)]
-            pub left: bool,
-        }
-
-        let data = BorderData::deserialize(deserializer)?;
-        let mut border = Border {
-            width: data.width,
-            color: data.color,
-            overlay: data.overlay,
-            top: data.top,
-            bottom: data.bottom,
-            left: data.left,
-            right: data.right,
-        };
-        if !border.top && !border.bottom && !border.left && !border.right {
-            border.top = true;
-            border.bottom = true;
-            border.left = true;
-            border.right = true;
-        }
-        Ok(border)
-    }
-}
-
 #[derive(Debug)]
 pub struct Path {
     pub bounds: RectF,
@@ -606,99 +561,6 @@ impl Layer {
     }
 }
 
-impl Border {
-    pub fn new(width: f32, color: Color) -> Self {
-        Self {
-            width,
-            color,
-            overlay: false,
-            top: false,
-            left: false,
-            bottom: false,
-            right: false,
-        }
-    }
-
-    pub fn all(width: f32, color: Color) -> Self {
-        Self {
-            width,
-            color,
-            overlay: false,
-            top: true,
-            left: true,
-            bottom: true,
-            right: true,
-        }
-    }
-
-    pub fn top(width: f32, color: Color) -> Self {
-        let mut border = Self::new(width, color);
-        border.top = true;
-        border
-    }
-
-    pub fn left(width: f32, color: Color) -> Self {
-        let mut border = Self::new(width, color);
-        border.left = true;
-        border
-    }
-
-    pub fn bottom(width: f32, color: Color) -> Self {
-        let mut border = Self::new(width, color);
-        border.bottom = true;
-        border
-    }
-
-    pub fn right(width: f32, color: Color) -> Self {
-        let mut border = Self::new(width, color);
-        border.right = true;
-        border
-    }
-
-    pub fn with_sides(mut self, top: bool, left: bool, bottom: bool, right: bool) -> Self {
-        self.top = top;
-        self.left = left;
-        self.bottom = bottom;
-        self.right = right;
-        self
-    }
-
-    pub fn top_width(&self) -> f32 {
-        if self.top {
-            self.width
-        } else {
-            0.0
-        }
-    }
-
-    pub fn left_width(&self) -> f32 {
-        if self.left {
-            self.width
-        } else {
-            0.0
-        }
-    }
-}
-
-impl ToJson for Border {
-    fn to_json(&self) -> serde_json::Value {
-        let mut value = json!({});
-        if self.top {
-            value["top"] = json!(self.width);
-        }
-        if self.right {
-            value["right"] = json!(self.width);
-        }
-        if self.bottom {
-            value["bottom"] = json!(self.width);
-        }
-        if self.left {
-            value["left"] = json!(self.width);
-        }
-        value
-    }
-}
-
 impl MouseRegion {
     pub fn id(&self) -> MouseRegionId {
         self.id

crates/gpui2/src/style.rs 🔗

@@ -16,7 +16,7 @@ use gpui::{
         rect::RectF, relative, AbsoluteLength, DefiniteLength, Edges, EdgesRefinement, Length,
         Point, PointRefinement, Size, SizeRefinement,
     },
-    taffy, WindowContext,
+    scene, taffy, WindowContext,
 };
 use gpui2_macros::styleable_helpers;
 use refineable::{Refineable, RefinementCascade};
@@ -63,7 +63,7 @@ pub struct Style {
     pub padding: Edges<DefiniteLength>,
     /// How large should the border be on each side?
     #[refineable]
-    pub border: Edges<DefiniteLength>,
+    pub border_widths: Edges<AbsoluteLength>,
 
     // Alignment properties
     /// How this node's children aligned in the cross/block axis?
@@ -92,6 +92,10 @@ pub struct Style {
 
     /// The fill color of this element
     pub fill: Option<Fill>,
+
+    /// The border color of this element
+    pub border_color: Option<Hsla>,
+
     /// The radius of the corners of this element
     #[refineable]
     pub corner_radii: CornerRadii,
@@ -143,7 +147,7 @@ impl Style {
             aspect_ratio: self.aspect_ratio,
             margin: self.margin.to_taffy(rem_size),
             padding: self.padding.to_taffy(rem_size),
-            border: self.border.to_taffy(rem_size),
+            border: self.border_widths.to_taffy(rem_size),
             align_items: self.align_items,
             align_self: self.align_self,
             align_content: self.align_content,
@@ -159,7 +163,6 @@ impl Style {
     }
 
     /// Paints the background of an element styled with this style.
-    /// Return the bounds in which to paint the content.
     pub fn paint_background<V: 'static>(&self, bounds: RectF, cx: &mut PaintContext<V>) {
         let rem_size = cx.rem_size();
         if let Some(color) = self.fill.as_ref().and_then(Fill::color) {
@@ -171,6 +174,29 @@ impl Style {
             });
         }
     }
+
+    /// Paints the foreground of an element styled with this style.
+    pub fn paint_foreground<V: 'static>(&self, bounds: RectF, cx: &mut PaintContext<V>) {
+        let rem_size = cx.rem_size();
+
+        if let Some(color) = self.border_color {
+            let border = self.border_widths.to_pixels(rem_size);
+            if !border.is_empty() {
+                cx.scene.push_quad(gpui::Quad {
+                    bounds,
+                    background: None,
+                    corner_radii: self.corner_radii.to_gpui(rem_size),
+                    border: scene::Border {
+                        color: color.into(),
+                        top: border.top,
+                        right: border.right,
+                        bottom: border.bottom,
+                        left: border.left,
+                    },
+                });
+            }
+        }
+    }
 }
 
 impl Default for Style {
@@ -186,7 +212,7 @@ impl Default for Style {
             inset: Edges::auto(),
             margin: Edges::<Length>::zero(),
             padding: Edges::<DefiniteLength>::zero(),
-            border: Edges::<DefiniteLength>::zero(),
+            border_widths: Edges::<AbsoluteLength>::zero(),
             size: Size::auto(),
             min_size: Size::auto(),
             max_size: Size::auto(),
@@ -204,6 +230,7 @@ impl Default for Style {
             flex_shrink: 1.0,
             flex_basis: Length::Auto,
             fill: None,
+            border_color: None,
             corner_radii: CornerRadii::default(),
             text_color: None,
             font_size: Some(1.),

crates/theme/src/theme.rs 🔗

@@ -6,9 +6,9 @@ pub mod ui;
 use components::{action_button::ButtonStyle, disclosure::DisclosureStyle, ToggleIconButtonStyle};
 use gpui::{
     color::Color,
-    elements::{ContainerStyle, ImageStyle, LabelStyle, Shadow, SvgStyle, TooltipStyle},
+    elements::{Border, ContainerStyle, ImageStyle, LabelStyle, Shadow, SvgStyle, TooltipStyle},
     fonts::{HighlightStyle, TextStyle},
-    platform, AppContext, AssetSource, Border, MouseState,
+    platform, AppContext, AssetSource, MouseState,
 };
 use parking_lot::Mutex;
 use schemars::JsonSchema;

crates/workspace/src/pane_group.rs 🔗

@@ -9,7 +9,7 @@ use gpui::{
     elements::*,
     geometry::{rect::RectF, vector::Vector2F},
     platform::{CursorStyle, MouseButton},
-    AnyViewHandle, Axis, Border, ModelHandle, ViewContext, ViewHandle,
+    AnyViewHandle, Axis, ModelHandle, ViewContext, ViewHandle,
 };
 use project::Project;
 use serde::Deserialize;