gpui: Add interval in pattern (#26459)

0x2CA created

Closes #ISSUE

[git: Use font size to determine pattern slash width
#26446](https://github.com/zed-industries/zed/pull/26446)

This PR only uses font size as the slant line width, and here it further
uses line height as the slant line interval control.

before


![image](https://github.com/user-attachments/assets/a8f2406e-5eed-4528-a9a2-867513613fc7)


now


![image](https://github.com/user-attachments/assets/9b8ccca9-8023-4cb2-a6fe-0e42e19642a4)

big line height


![image](https://github.com/user-attachments/assets/4498e858-4f25-432c-80ee-355726d9c41b)


Release Notes:

- N/A *or* Added/Fixed/Improved ...

Change summary

crates/gpui/examples/pattern.rs             | 88 ++++++++++------------
crates/gpui/src/color.rs                    |  6 +
crates/gpui/src/platform/blade/shaders.wgsl |  7 +
crates/gpui/src/platform/mac/shaders.metal  |  7 +
4 files changed, 55 insertions(+), 53 deletions(-)

Detailed changes

crates/gpui/examples/pattern.rs 🔗

@@ -25,30 +25,26 @@ impl Render for PatternExample {
                     .flex_col()
                     .border_1()
                     .border_color(gpui::blue())
-                    .child(
-                        div()
-                            .w(px(54.0))
-                            .h(px(18.0))
-                            .bg(pattern_slash(gpui::red(), 18.0 / 2.0)),
-                    )
-                    .child(
-                        div()
-                            .w(px(54.0))
-                            .h(px(18.0))
-                            .bg(pattern_slash(gpui::red(), 18.0 / 2.0)),
-                    )
-                    .child(
-                        div()
-                            .w(px(54.0))
-                            .h(px(18.0))
-                            .bg(pattern_slash(gpui::red(), 18.0 / 2.0)),
-                    )
-                    .child(
-                        div()
-                            .w(px(54.0))
-                            .h(px(18.0))
-                            .bg(pattern_slash(gpui::red(), 18.0 / 2.0)),
-                    ),
+                    .child(div().w(px(54.0)).h(px(18.0)).bg(pattern_slash(
+                        gpui::red(),
+                        18.0 / 4.0,
+                        18.0 / 4.0,
+                    )))
+                    .child(div().w(px(54.0)).h(px(18.0)).bg(pattern_slash(
+                        gpui::red(),
+                        18.0 / 4.0,
+                        18.0 / 4.0,
+                    )))
+                    .child(div().w(px(54.0)).h(px(18.0)).bg(pattern_slash(
+                        gpui::red(),
+                        18.0 / 4.0,
+                        18.0 / 4.0,
+                    )))
+                    .child(div().w(px(54.0)).h(px(18.0)).bg(pattern_slash(
+                        gpui::red(),
+                        18.0 / 4.0,
+                        18.0 / 2.0,
+                    ))),
             )
             .child(
                 div()
@@ -58,30 +54,26 @@ impl Render for PatternExample {
                     .border_color(gpui::blue())
                     .bg(gpui::green().opacity(0.16))
                     .child("Elements the same height should align")
-                    .child(
-                        div()
-                            .w(px(256.0))
-                            .h(px(56.0))
-                            .bg(pattern_slash(gpui::red(), 56.0 / 3.0)),
-                    )
-                    .child(
-                        div()
-                            .w(px(256.0))
-                            .h(px(56.0))
-                            .bg(pattern_slash(gpui::green(), 56.0 / 3.0)),
-                    )
-                    .child(
-                        div()
-                            .w(px(256.0))
-                            .h(px(56.0))
-                            .bg(pattern_slash(gpui::blue(), 56.0 / 3.0)),
-                    )
-                    .child(
-                        div()
-                            .w(px(256.0))
-                            .h(px(26.0))
-                            .bg(pattern_slash(gpui::yellow(), 56.0 / 3.0)),
-                    ),
+                    .child(div().w(px(256.0)).h(px(56.0)).bg(pattern_slash(
+                        gpui::red(),
+                        56.0 / 6.0,
+                        56.0 / 6.0,
+                    )))
+                    .child(div().w(px(256.0)).h(px(56.0)).bg(pattern_slash(
+                        gpui::green(),
+                        56.0 / 6.0,
+                        56.0 / 6.0,
+                    )))
+                    .child(div().w(px(256.0)).h(px(56.0)).bg(pattern_slash(
+                        gpui::blue(),
+                        56.0 / 6.0,
+                        56.0 / 6.0,
+                    )))
+                    .child(div().w(px(256.0)).h(px(26.0)).bg(pattern_slash(
+                        gpui::yellow(),
+                        56.0 / 6.0,
+                        56.0 / 6.0,
+                    ))),
             )
             .child(
                 div()

crates/gpui/src/color.rs 🔗

@@ -683,7 +683,11 @@ impl Default for Background {
 }
 
 /// Creates a hash pattern background
-pub fn pattern_slash(color: Hsla, height: f32) -> Background {
+pub fn pattern_slash(color: Hsla, width: f32, interval: f32) -> Background {
+    let width_scaled = (width * 255.0) as u32;
+    let interval_scaled = (interval * 255.0) as u32;
+    let height = ((width_scaled * 0xFFFF) + interval_scaled) as f32;
+
     Background {
         tag: BackgroundTag::PatternSlash,
         solid: color,

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

@@ -360,7 +360,10 @@ fn gradient_color(background: Background, position: vec2<f32>, bounds: Bounds,
             }
         }
         case 2u: {
-            let pattern_height = background.gradient_angle_or_pattern_height;
+            let gradient_angle_or_pattern_height = background.gradient_angle_or_pattern_height;
+            let pattern_width = (gradient_angle_or_pattern_height / 65535.0f) / 255.0f;
+            let pattern_interval = (gradient_angle_or_pattern_height % 65535.0f) / 255.0f;
+            let pattern_height = pattern_width + pattern_interval;
             let stripe_angle = M_PI_F / 4.0;
             let pattern_period = pattern_height * sin(stripe_angle);
             let rotation = mat2x2<f32>(
@@ -370,7 +373,7 @@ fn gradient_color(background: Background, position: vec2<f32>, bounds: Bounds,
             let relative_position = position - bounds.origin;
             let rotated_point = rotation * relative_position;
             let pattern = rotated_point.x % pattern_period;
-            let distance = min(pattern, pattern_period - pattern) - pattern_period / 4;
+            let distance = min(pattern, pattern_period - pattern) - pattern_period * (pattern_width / pattern_height) /  2.0f;
             background_color = solid_color;
             background_color.a *= saturate(0.5 - distance);
         }

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

@@ -875,14 +875,17 @@ float4 fill_color(Background background,
       break;
     }
     case 2: {
-        float pattern_height = background.gradient_angle_or_pattern_height;
+        float gradient_angle_or_pattern_height = background.gradient_angle_or_pattern_height;
+        float pattern_width = (gradient_angle_or_pattern_height / 65535.0f) / 255.0f;
+        float pattern_interval = fmod(gradient_angle_or_pattern_height, 65535.0f) / 255.0f;
+        float pattern_height = pattern_width + pattern_interval;
         float stripe_angle = M_PI_F / 4.0;
         float pattern_period = pattern_height * sin(stripe_angle);
         float2x2 rotation = rotate2d(stripe_angle);
         float2 relative_position = position - float2(bounds.origin.x, bounds.origin.y);
         float2 rotated_point = rotation * relative_position;
         float pattern = fmod(rotated_point.x, pattern_period);
-        float distance = min(pattern, pattern_period - pattern) - pattern_period / 4.0;
+        float distance = min(pattern, pattern_period - pattern) - pattern_period * (pattern_width / pattern_height) /  2.0f;
         color = solid_color;
         color.a *= saturate(0.5 - distance);
         break;