Allow tinting images grayscale

Antonio Scandurra created

Change summary

crates/gpui3/src/assets.rs                  | 3 +--
crates/gpui3/src/elements/img.rs            | 9 ++++++++-
crates/gpui3/src/platform/mac/shaders.metal | 6 ++++++
crates/gpui3/src/scene.rs                   | 1 +
crates/gpui3/src/window.rs                  | 2 ++
crates/storybook2/src/collab_panel.rs       | 4 ++--
6 files changed, 20 insertions(+), 5 deletions(-)

Detailed changes

crates/gpui3/src/assets.rs 🔗

@@ -3,9 +3,8 @@ use anyhow::anyhow;
 use image::{Bgra, ImageBuffer};
 use std::{
     borrow::Cow,
-    cmp::Ordering,
     fmt,
-    hash::{Hash, Hasher},
+    hash::Hash,
     sync::atomic::{AtomicUsize, Ordering::SeqCst},
 };
 

crates/gpui3/src/elements/img.rs 🔗

@@ -9,6 +9,7 @@ use util::ResultExt;
 pub struct Img<S> {
     style: RefinementCascade<Style>,
     uri: Option<SharedString>,
+    grayscale: bool,
     state_type: PhantomData<S>,
 }
 
@@ -16,6 +17,7 @@ pub fn img<S>() -> Img<S> {
     Img {
         style: RefinementCascade::default(),
         uri: None,
+        grayscale: false,
         state_type: PhantomData,
     }
 }
@@ -25,6 +27,11 @@ impl<S> Img<S> {
         self.uri = Some(uri.into());
         self
     }
+
+    pub fn grayscale(mut self, grayscale: bool) -> Self {
+        self.grayscale = grayscale;
+        self
+    }
 }
 
 impl<S: 'static> Element for Img<S> {
@@ -64,7 +71,7 @@ impl<S: 'static> Element for Img<S> {
                 .now_or_never()
                 .and_then(ResultExt::log_err)
             {
-                cx.paint_image(bounds, order, data, false)?;
+                cx.paint_image(bounds, order, data, self.grayscale)?;
             } else {
                 log::warn!("image not loaded yet");
                 // cx.spawn(|this, mut cx| async move {

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

@@ -191,6 +191,12 @@ fragment float4 polychrome_sprite_fragment(
   float clip_distance = quad_sdf(input.position.xy, sprite.content_mask.bounds,
                                  sprite.content_mask.corner_radii);
   float4 color = sample;
+  if (sprite.grayscale) {
+    float grayscale = 0.2126 * color.r + 0.7152 * color.g + 0.0722 * color.b;
+    color.r = grayscale;
+    color.g = grayscale;
+    color.b = grayscale;
+  }
   color.a *= saturate(0.5 - clip_distance);
   return color;
 }

crates/gpui3/src/scene.rs 🔗

@@ -276,6 +276,7 @@ pub struct PolychromeSprite {
     pub bounds: Bounds<ScaledPixels>,
     pub content_mask: ScaledContentMask,
     pub tile: AtlasTile,
+    pub grayscale: bool,
 }
 
 impl Ord for PolychromeSprite {

crates/gpui3/src/window.rs 🔗

@@ -305,6 +305,7 @@ impl<'a, 'w> WindowContext<'a, 'w> {
                     bounds,
                     content_mask,
                     tile,
+                    grayscale: false,
                 },
             );
         }
@@ -379,6 +380,7 @@ impl<'a, 'w> WindowContext<'a, 'w> {
                 bounds,
                 content_mask,
                 tile,
+                grayscale,
             },
         );
 

crates/storybook2/src/collab_panel.rs 🔗

@@ -1,7 +1,7 @@
 use crate::theme::{theme, Theme};
 use gpui3::{
-    div, img, svg, view, AppContext, ArcCow, Context, Element, IntoAnyElement, ParentElement,
-    ScrollState, SharedString, StyleHelpers, View, ViewContext, WindowContext,
+    div, img, svg, view, AppContext, Context, Element, IntoAnyElement, ParentElement, ScrollState,
+    SharedString, StyleHelpers, View, ViewContext, WindowContext,
 };
 
 pub struct CollabPanel {