gpui: Add alpha method to Rgba (#52125)

## Context

GPUI API change only: 
  - added `.alpha(a: f32)` method to `RGBA`
  - added `.opacity(factor: f32)` method to `RGBA`
  - added documentation for both new methods
  - added test coverage for both methods
  
These implementations already exist for the `HSLA` struct and were
missing for `RGBA`.

> [!NOTE]
> In my opinion, a trait implementation could be beneficial here. Let me
know what you think about that idea before I end up making unwanted
changes.

## How to Review

Just added the new methods, including documentation and test coverage.

## Self-Review Checklist

<!-- Check before requesting review: -->
- [x] I've reviewed my own diff for quality, security, and reliability
- [x] Unsafe blocks (if any) have justifying comments
- [x] The content is consistent with the [UI/UX
checklist](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable

Release Notes:

- Added `gpui::Rgba::alpha` and `gpui::Rgba::opacity` methods for
setting and scaling a color's alpha channel, matching the existing
`gpui::Hsla` API

---------

Co-authored-by: dino <dinojoaocosta@gmail.com>
This commit is contained in:
Sebastian Kootzanddino authored and GitHub committed 2026-06-11 17:27:25 +00:00
1 parent 6f42904133
commit c42de9955c
2 files changed
+94 -13

No files matched your search

+6 -12
View File
@@ -67,8 +67,7 @@ impl PaintingViewer {
builder.line_to(point(px(50.), px(130.)));
builder.close();
let path = builder.build().unwrap();
let mut red = rgb(0xFF0000);
red.a = 0.5;
let red = rgb(0xFF0000).alpha(0.5);
lines.push((path, red.into()));
// 50% opaque blue path that extends across black quad.
@@ -79,8 +78,7 @@ impl PaintingViewer {
builder.line_to(point(px(150.), px(130.)));
builder.close();
let path = builder.build().unwrap();
let mut blue = rgb(0x0000FF);
blue.a = 0.5;
let blue = rgb(0x0000FF).alpha(0.5);
lines.push((path, blue.into()));
// 50% opaque green path that extends across black quad.
@@ -91,8 +89,7 @@ impl PaintingViewer {
builder.line_to(point(px(250.), px(130.)));
builder.close();
let path = builder.build().unwrap();
let mut green = rgb(0x00FF00);
green.a = 0.5;
let green = rgb(0x00FF00).alpha(0.5);
lines.push((path, green.into()));
// 50% opaque black path that extends across black quad.
@@ -103,8 +100,7 @@ impl PaintingViewer {
builder.line_to(point(px(350.), px(130.)));
builder.close();
let path = builder.build().unwrap();
let mut black = rgb(0x000000);
black.a = 0.5;
let black = rgb(0x000000).alpha(0.5);
lines.push((path, black.into()));
// Two 50% opaque red circles overlapping - center should be darker red
@@ -128,8 +124,7 @@ impl PaintingViewer {
);
builder.close();
let path = builder.build().unwrap();
let mut red1 = rgb(0xFF0000);
red1.a = 0.5;
let red1 = rgb(0xFF0000).alpha(0.5);
lines.push((path, red1.into()));
let mut builder = PathBuilder::fill();
@@ -152,8 +147,7 @@ impl PaintingViewer {
);
builder.close();
let path = builder.build().unwrap();
let mut red2 = rgb(0xFF0000);
red2.a = 0.5;
let red2 = rgb(0xFF0000).alpha(0.5);
lines.push((path, red2.into()));
// draw a Rust logo
+88 -1
View File
@@ -69,6 +69,68 @@ impl Rgba {
}
}
}
/// Returns a new RGBA color with the same red, green and blue channels, but
/// with a new alpha value.
///
/// Example:
/// ```
/// use gpui::rgba;
/// let color = rgba(0xFF0000FF);
/// let faded = color.alpha(0.25);
/// assert_eq!(faded.a, 0.25);
/// ```
///
/// This will return a red color with 25% opacity.
///
/// Example:
/// ```
/// use gpui::rgba;
/// let color = rgba(0x3399FFCC);
/// let transparent = color.alpha(0.0);
/// assert_eq!(transparent.a, 0.0);
/// ```
///
/// This will return the same blue color, fully transparent.
pub fn alpha(&self, a: f32) -> Self {
Rgba {
r: self.r,
g: self.g,
b: self.b,
a: a.clamp(0., 1.),
}
}
/// Returns a new RGBA color with the same red, green, and blue channels,
/// but with the alpha channel multiplied by the given factor.
///
/// Example:
/// ```
/// use gpui::rgba;
/// let color = rgba(0xFF0000FF); // Fully opaque red
/// let faded = color.opacity(0.5);
/// assert_eq!(faded.a, 0.5);
/// ```
///
/// This will return a red color with 50% opacity.
///
/// Example:
/// ```
/// use gpui::rgba;
/// let color = rgba(0x3399FFCC); // A light blue with 80% opacity
/// let faded = color.opacity(0.5);
/// assert!((faded.a - 0.4).abs() < 1e-6);
/// ```
///
/// This will return the same blue color scaled down to 40% opacity.
pub fn opacity(&self, factor: f32) -> Self {
Rgba {
r: self.r,
g: self.g,
b: self.b,
a: self.a * factor.clamp(0., 1.),
}
}
}
impl From<Rgba> for u32 {
@@ -591,7 +653,7 @@ impl Hsla {
/// assert_eq!(red_color.a, 0.25);
/// ```
///
/// This will return a red color with half the opacity.
/// This will return a red color with 25% opacity.
///
/// Example:
/// ```
@@ -979,4 +1041,29 @@ mod tests {
assert!(!background.is_transparent());
assert!(background.opacity(0.0).is_transparent());
}
#[test]
fn test_rgba_alpha() {
let color = Rgba {
r: 0.2,
g: 0.6,
b: 1.0,
a: 0.8,
};
assert_eq!(color.alpha(0.25).a, 0.25);
assert_eq!(color.alpha(1.5).a, 1.0);
}
#[test]
fn test_rgba_opacity() {
let color = Rgba {
r: 0.2,
g: 0.6,
b: 1.0,
a: 0.8,
};
assert!((color.opacity(0.5).a - 0.4).abs() < 1e-6);
assert_eq!(color.opacity(2.0).a, 0.8);
}
}