Revert "gpui & ui: Use shader for dashed dividers" (#23850)

Nate Butler created

Reverts zed-industries/zed#23839

getting some reports of linux crashes – will investigate later today

Release Notes:

- N/A

Change summary

.zed/settings.json                          |   1 
crates/gpui/examples/pattern.rs             |  57 ------------
crates/gpui/src/color.rs                    |  44 ---------
crates/gpui/src/platform/blade/shaders.wgsl |  16 ---
crates/gpui/src/platform/mac/shaders.metal  |  25 +----
crates/gpui/src/style.rs                    |   1 
crates/ui/src/components/divider.rs         | 102 ++++++++++++++--------
crates/workspace/src/theme_preview.rs       |   2 
8 files changed, 72 insertions(+), 176 deletions(-)

Detailed changes

.zed/settings.json 🔗

@@ -39,7 +39,6 @@
     }
   },
   "file_types": {
-    "C": ["metal"],
     "Dockerfile": ["Dockerfile*[!dockerignore]"],
     "Git Ignore": ["dockerignore"]
   },

crates/gpui/examples/pattern.rs 🔗

@@ -1,7 +1,6 @@
 use gpui::{
-    div, linear_color_stop, linear_gradient, pattern_horizontal_dash, pattern_slash,
-    pattern_vertical_dash, prelude::*, px, rgb, size, App, AppContext, Application, Bounds,
-    Context, Window, WindowBounds, WindowOptions,
+    div, linear_color_stop, linear_gradient, pattern_slash, prelude::*, px, rgb, size, App,
+    AppContext, Application, Bounds, Context, Window, WindowBounds, WindowOptions,
 };
 
 struct PatternExample;
@@ -20,58 +19,6 @@ impl Render for PatternExample {
             .text_xl()
             .text_color(rgb(0x000000))
             .child("Pattern Example")
-            .child(
-                div()
-                    .flex()
-                    .gap_4()
-                    .child(
-                        div()
-                            .flex()
-                            .flex_col()
-                            .gap_1()
-                            .child(
-                                div()
-                                    .w(px(160.0))
-                                    .h(px(1.0))
-                                    .bg(pattern_horizontal_dash(gpui::red())),
-                            )
-                            .child(
-                                div()
-                                    .w(px(160.0))
-                                    .h(px(4.0))
-                                    .bg(pattern_horizontal_dash(gpui::red())),
-                            )
-                            .child(
-                                div()
-                                    .w(px(160.0))
-                                    .h(px(8.0))
-                                    .bg(pattern_horizontal_dash(gpui::red())),
-                            ),
-                    )
-                    .child(
-                        div()
-                            .flex()
-                            .gap_1()
-                            .child(
-                                div()
-                                    .w(px(1.0))
-                                    .h(px(160.0))
-                                    .bg(pattern_vertical_dash(gpui::blue())),
-                            )
-                            .child(
-                                div()
-                                    .w(px(4.0))
-                                    .h(px(160.0))
-                                    .bg(pattern_vertical_dash(gpui::blue())),
-                            )
-                            .child(
-                                div()
-                                    .w(px(8.0))
-                                    .h(px(160.0))
-                                    .bg(pattern_vertical_dash(gpui::blue())),
-                            ),
-                    ),
-            )
             .child(
                 div()
                     .flex()

crates/gpui/src/color.rs 🔗

@@ -548,33 +548,12 @@ impl<'de> Deserialize<'de> for Hsla {
     }
 }
 
-/// The orientation of a background.
-#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
-#[repr(C)]
-pub enum BackgroundOrientation {
-    /// The background is oriented horizontally.
-    #[default]
-    Horizontal = 0,
-    /// The background is oriented vertically.
-    Vertical = 1,
-}
-
-impl Display for BackgroundOrientation {
-    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
-        match self {
-            BackgroundOrientation::Horizontal => write!(f, "Horizontal"),
-            BackgroundOrientation::Vertical => write!(f, "Vertical"),
-        }
-    }
-}
-
 #[derive(Debug, Clone, Copy, PartialEq)]
 #[repr(C)]
 pub(crate) enum BackgroundTag {
     Solid = 0,
     LinearGradient = 1,
     PatternSlash = 2,
-    PatternDash = 3,
 }
 
 /// A color space for color interpolation.
@@ -610,7 +589,6 @@ pub struct Background {
     pub(crate) solid: Hsla,
     pub(crate) angle: f32,
     pub(crate) colors: [LinearColorStop; 2],
-    pub(crate) orientation: BackgroundOrientation,
     /// Padding for alignment for repr(C) layout.
     pad: u32,
 }
@@ -624,7 +602,6 @@ impl Default for Background {
             color_space: ColorSpace::default(),
             angle: 0.0,
             colors: [LinearColorStop::default(), LinearColorStop::default()],
-            orientation: BackgroundOrientation::default(),
             pad: 0,
         }
     }
@@ -639,26 +616,6 @@ pub fn pattern_slash(color: Hsla) -> Background {
     }
 }
 
-/// Creates a dash pattern background
-pub fn pattern_horizontal_dash(color: Hsla) -> Background {
-    Background {
-        tag: BackgroundTag::PatternDash,
-        orientation: BackgroundOrientation::Horizontal,
-        solid: color,
-        ..Default::default()
-    }
-}
-
-/// Creates a vertical dash pattern background
-pub fn pattern_vertical_dash(color: Hsla) -> Background {
-    Background {
-        tag: BackgroundTag::PatternDash,
-        solid: color,
-        orientation: BackgroundOrientation::Vertical,
-        ..Default::default()
-    }
-}
-
 /// Creates a LinearGradient background color.
 ///
 /// The gradient line's angle of direction. A value of `0.` is equivalent to to top; increasing values rotate clockwise from there.
@@ -737,7 +694,6 @@ impl Background {
             BackgroundTag::Solid => self.solid.is_transparent(),
             BackgroundTag::LinearGradient => self.colors.iter().all(|c| c.color.is_transparent()),
             BackgroundTag::PatternSlash => self.solid.is_transparent(),
-            BackgroundTag::PatternDash => self.solid.is_transparent(),
         }
     }
 }

crates/gpui/src/platform/blade/shaders.wgsl 🔗

@@ -359,7 +359,6 @@ fn gradient_color(background: Background, position: vec2<f32>, bounds: Bounds,
             }
         }
         case 2u: {
-            // Slash pattern
             let base_pattern_size = bounds.size.y / 5.0;
             let width = base_pattern_size * 0.5;
             let slash_spacing = 0.89;
@@ -375,21 +374,6 @@ fn gradient_color(background: Background, position: vec2<f32>, bounds: Bounds,
             background_color = sold_color;
             background_color.a *= saturate(0.5 - distance);
         }
-        case 3u: {
-            // Dash pattern
-            let dash_width = 8.0;
-            let gap_width = 8.0;
-            let pattern_width = dash_width + gap_width;
-            let relative_position = position - bounds.origin;
-
-            // Use a dot product to select x or y based on orientation
-            let orientation_vector = vec2<f32>(1.0 - f32(background.angle != 0.0), f32(background.angle != 0.0));
-            let pattern_position = fmod(dot(relative_position, orientation_vector), pattern_width);
-
-            let distance = pattern_position - dash_width;
-            background_color = sold_color;
-            background_color.a *= step(-distance, 0.0);
-        }
     }
 
     return background_color;

crates/gpui/src/platform/mac/shaders.metal 🔗

@@ -797,7 +797,7 @@ float4 over(float4 below, float4 above) {
 GradientColor prepare_fill_color(uint tag, uint color_space, Hsla solid,
                                      Hsla color0, Hsla color1) {
   GradientColor out;
-  if (tag == 0 || tag == 2 || tag == 3) {
+  if (tag == 0 || tag == 2) {
     out.solid = hsla_to_rgba(solid);
   } else if (tag == 1) {
     out.color0 = hsla_to_rgba(color0);
@@ -874,10 +874,13 @@ float4 fill_color(Background background,
       break;
     }
     case 2: {
-        // Slash pattern
+        // This pattern is full of magic numbers to make it line up perfectly
+        // when vertically stacked. Make sure you know what you are doing
+        // if you change this!
+
         float base_pattern_size = bounds.size.height / 5;
         float width = base_pattern_size * 0.5;
-        float slash_spacing = .89; // exact number to make vertical elements line up
+        float slash_spacing = .89;
         float radians = M_PI_F / 4.0;
         float2x2 rotation = rotate2d(radians);
         float2 relative_position = position - float2(bounds.origin.x, bounds.origin.y);
@@ -888,22 +891,6 @@ float4 fill_color(Background background,
         color.a *= saturate(0.5 - distance);
         break;
     }
-    case 3: {
-        // Dash pattern
-        float dash_width = 8.0;
-        float gap_width = 8.0;
-        float pattern_width = dash_width + gap_width;
-        float2 relative_position = position - float2(bounds.origin.x, bounds.origin.y);
-
-        // Use a dot product to select x or y based on orientation
-        float2 orientation_vector = float2(1.0 - background.orientation, background.orientation);
-        float pattern_position = fmod(dot(relative_position, orientation_vector), pattern_width);
-
-        float distance = pattern_position - dash_width;
-        color = solid_color;
-        color.a *= step(-distance, 0.0);
-        break;
-    }
   }
 
   return color;

crates/gpui/src/style.rs 🔗

@@ -583,7 +583,6 @@ impl Style {
                         .map(|stop| stop.color)
                         .unwrap_or_default(),
                     BackgroundTag::PatternSlash => color.solid,
-                    BackgroundTag::PatternDash => color.solid,
                 },
                 None => Hsla::default(),
             };

crates/ui/src/components/divider.rs 🔗

@@ -1,7 +1,14 @@
-use gpui::{pattern_horizontal_dash, pattern_vertical_dash, Background, Hsla, IntoElement};
+#![allow(missing_docs)]
+use gpui::{Hsla, IntoElement};
 
 use crate::prelude::*;
 
+#[derive(Clone, Copy, PartialEq)]
+enum DividerStyle {
+    Solid,
+    Dashed,
+}
+
 #[derive(Clone, Copy, PartialEq)]
 enum DividerDirection {
     Horizontal,
@@ -11,15 +18,12 @@ enum DividerDirection {
 /// The color of a [`Divider`].
 #[derive(Default)]
 pub enum DividerColor {
-    /// The default border color.
-    #[default]
     Border,
-    /// Usually a de-emphasized border color.
+    #[default]
     BorderVariant,
 }
 
 impl DividerColor {
-    /// Returns the divider's HSLA color.
     pub fn hsla(self, cx: &mut App) -> Hsla {
         match self {
             DividerColor::Border => cx.theme().colors().border,
@@ -28,92 +32,112 @@ impl DividerColor {
     }
 }
 
-/// A component that can be used to separate sections of content.
-///
-/// Can be rendered horizontally or vertically.
 #[derive(IntoElement)]
 pub struct Divider {
+    style: DividerStyle,
     direction: DividerDirection,
     color: DividerColor,
     inset: bool,
-    is_dashed: bool,
 }
 
 impl RenderOnce for Divider {
     fn render(self, _: &mut Window, cx: &mut App) -> impl IntoElement {
-        let color = self.color.hsla(cx);
-        let background = if self.is_dashed {
-            match self.direction {
-                DividerDirection::Horizontal => pattern_horizontal_dash(color),
-                DividerDirection::Vertical => pattern_vertical_dash(color),
-            }
-        } else {
-            Background::from(color)
-        };
-
-        div()
-            .map(|this| match self.direction {
-                DividerDirection::Horizontal => {
-                    this.h_px().w_full().when(self.inset, |this| this.mx_1p5())
-                }
-                DividerDirection::Vertical => {
-                    this.w_px().h_full().when(self.inset, |this| this.my_1p5())
-                }
-            })
-            .bg(background)
+        match self.style {
+            DividerStyle::Solid => self.render_solid(cx).into_any_element(),
+            DividerStyle::Dashed => self.render_dashed(cx).into_any_element(),
+        }
     }
 }
 
 impl Divider {
-    /// Creates a solid horizontal divider.
     pub fn horizontal() -> Self {
         Self {
+            style: DividerStyle::Solid,
             direction: DividerDirection::Horizontal,
             color: DividerColor::default(),
             inset: false,
-            is_dashed: false,
         }
     }
 
-    /// Creates a solid vertical divider.
     pub fn vertical() -> Self {
         Self {
+            style: DividerStyle::Solid,
             direction: DividerDirection::Vertical,
             color: DividerColor::default(),
             inset: false,
-            is_dashed: false,
         }
     }
 
-    /// Creates a dashed horizontal divider.
     pub fn horizontal_dashed() -> Self {
         Self {
+            style: DividerStyle::Dashed,
             direction: DividerDirection::Horizontal,
             color: DividerColor::default(),
             inset: false,
-            is_dashed: true,
         }
     }
 
-    /// Creates a dashed vertical divider.
     pub fn vertical_dashed() -> Self {
         Self {
+            style: DividerStyle::Dashed,
             direction: DividerDirection::Vertical,
             color: DividerColor::default(),
             inset: false,
-            is_dashed: true,
         }
     }
 
-    /// Pads the divider with a margin.
     pub fn inset(mut self) -> Self {
         self.inset = true;
         self
     }
 
-    /// Sets the color of the divider.
     pub fn color(mut self, color: DividerColor) -> Self {
         self.color = color;
         self
     }
+
+    pub fn render_solid(self, cx: &mut App) -> impl IntoElement {
+        div()
+            .map(|this| match self.direction {
+                DividerDirection::Horizontal => {
+                    this.h_px().w_full().when(self.inset, |this| this.mx_1p5())
+                }
+                DividerDirection::Vertical => {
+                    this.w_px().h_full().when(self.inset, |this| this.my_1p5())
+                }
+            })
+            .bg(self.color.hsla(cx))
+    }
+
+    // TODO: Use canvas or a shader here
+    // This obviously is a short term approach
+    pub fn render_dashed(self, cx: &mut App) -> impl IntoElement {
+        let segment_count = 128;
+        let segment_count_f = segment_count as f32;
+        let segment_min_w = 6.;
+        let base = match self.direction {
+            DividerDirection::Horizontal => h_flex(),
+            DividerDirection::Vertical => v_flex(),
+        };
+        let (w, h) = match self.direction {
+            DividerDirection::Horizontal => (px(segment_min_w), px(1.)),
+            DividerDirection::Vertical => (px(1.), px(segment_min_w)),
+        };
+        let color = self.color.hsla(cx);
+        let total_min_w = segment_min_w * segment_count_f * 2.; // * 2 because of the gap
+
+        base.min_w(px(total_min_w))
+            .map(|this| {
+                if self.direction == DividerDirection::Horizontal {
+                    this.w_full().h_px()
+                } else {
+                    this.w_px().h_full()
+                }
+            })
+            .gap(px(segment_min_w))
+            .overflow_hidden()
+            .children(
+                (0..segment_count).map(|_| div().flex_grow().flex_shrink_0().w(w).h(h).bg(color)),
+            )
+    }
 }

crates/workspace/src/theme_preview.rs 🔗

@@ -5,7 +5,7 @@ use theme::all_theme_colors;
 use ui::{
     element_cell, prelude::*, string_cell, utils::calculate_contrast_ratio, AudioStatus,
     Availability, Avatar, AvatarAudioStatusIndicator, AvatarAvailabilityIndicator, ButtonLike,
-    Checkbox, CheckboxWithLabel, ContentGroup, DecoratedIcon, Divider, ElevationIndex, Facepile,
+    Checkbox, CheckboxWithLabel, ContentGroup, DecoratedIcon, ElevationIndex, Facepile,
     IconDecoration, Indicator, Switch, Table, TintColor, Tooltip,
 };