use std::{any::Any, fmt, sync::Arc};
use crate::{BorderStyle, Quad};
use gpui_types::{Background, Bounds, ContentMask, Corners, DrawOrder, Edges, Hsla, ScaledPixels};
#[derive(Clone)]
pub struct ImportedTextureHandle {
pub payload: Arc<dyn Any + Send + Sync>,
}
impl ImportedTextureHandle {
pub fn new(payload: impl Any + Send + Sync) -> Self {
Self {
payload: Arc::new(payload),
}
}
}
impl fmt::Debug for ImportedTextureHandle {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str("ImportedTextureHandle")
}
}
#[derive(Clone)]
pub enum CustomRenderPrimitive {
Texture {
order: DrawOrder,
handle: ImportedTextureHandle,
bounds: Bounds<ScaledPixels>,
content_mask: ContentMask<ScaledPixels>,
radii: Corners<ScaledPixels>,
opacity: f32,
flip_v: bool,
},
}
impl CustomRenderPrimitive {
pub fn order(&self) -> DrawOrder {
match self {
Self::Texture { order, .. } => *order,
}
}
pub fn order_mut(&mut self) -> &mut DrawOrder {
match self {
Self::Texture { order, .. } => order,
}
}
pub fn bounds(&self) -> &Bounds<ScaledPixels> {
match self {
Self::Texture { bounds, .. } => bounds,
}
}
pub fn content_mask(&self) -> &ContentMask<ScaledPixels> {
match self {
Self::Texture { content_mask, .. } => content_mask,
}
}
pub fn to_quad_record(&self) -> Quad {
match self {
Self::Texture {
order,
bounds,
content_mask,
radii,
opacity,
flip_v,
..
} => {
let mut background = Background::default();
background.solid = Hsla {
h: 0.0,
s: 0.0,
l: 0.0,
a: *opacity,
};
Quad {
order: *order,
border_style: if *flip_v {
BorderStyle::Dashed
} else {
BorderStyle::Solid
},
bounds: *bounds,
content_mask: *content_mask,
background,
border_color: Hsla::default(),
corner_radii: *radii,
border_widths: Edges::default(),
}
}
}
}
}
impl fmt::Debug for CustomRenderPrimitive {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Texture {
handle,
bounds,
opacity,
flip_v,
..
} => formatter
.debug_struct("Texture")
.field("handle", handle)
.field("bounds", bounds)
.field("opacity", opacity)
.field("flip_v", flip_v)
.finish_non_exhaustive(),
}
}
}
#[cfg(target_os = "macos")]
#[derive(Clone, Copy)]
pub struct MetalTexture(pub *mut std::ffi::c_void);
#[cfg(target_os = "macos")]
unsafe impl Send for MetalTexture {}
#[cfg(target_os = "macos")]
unsafe impl Sync for MetalTexture {}
#[cfg(test)]
mod tests {
use super::*;
use gpui_types::{Point, Size};
fn bounds(x: f32, y: f32, width: f32, height: f32) -> Bounds<ScaledPixels> {
Bounds {
origin: Point {
x: ScaledPixels(x),
y: ScaledPixels(y),
},
size: Size {
width: ScaledPixels(width),
height: ScaledPixels(height),
},
}
}
fn texture(
bounds: Bounds<ScaledPixels>,
radii: Corners<ScaledPixels>,
opacity: f32,
flip_v: bool,
) -> CustomRenderPrimitive {
CustomRenderPrimitive::Texture {
order: 0,
handle: ImportedTextureHandle::new(()),
bounds,
content_mask: ContentMask { bounds },
radii,
opacity,
flip_v,
}
}
#[test]
fn a_texture_primitive_encodes_into_the_quad_record() {
let bounds = bounds(1.0, 2.0, 3.0, 4.0);
let radii = Corners {
top_left: ScaledPixels(5.0),
top_right: ScaledPixels(6.0),
bottom_right: ScaledPixels(7.0),
bottom_left: ScaledPixels(8.0),
};
let quad = texture(bounds, radii, 0.25, true).to_quad_record();
assert_eq!(quad.bounds, bounds);
assert_eq!(quad.content_mask, ContentMask { bounds });
assert_eq!(quad.corner_radii, radii);
assert_eq!(
quad.background.solid.a, 0.25,
"the opacity rides in the solid background's alpha"
);
assert_eq!(
quad.border_style,
BorderStyle::Dashed,
"flip_v rides in the border style"
);
}
#[test]
fn a_texture_primitive_without_a_flip_encodes_a_solid_border_style() {
let bounds = bounds(0.0, 0.0, 10.0, 10.0);
let quad = texture(bounds, Corners::default(), 1.0, false).to_quad_record();
assert_eq!(quad.border_style, BorderStyle::Solid);
assert_eq!(quad.background.solid.a, 1.0);
}
}