use gpui::{
AbsoluteLength, AnyElement, App, Bounds, Corners, Element, GlobalElementId, InspectorElementId,
IntoElement, LayoutId, Pixels, Styled, Window, fill, px,
};
use theme::Theme;
pub const MENU_BLUR: f32 = 44.0;
pub const PANEL_BLUR: f32 = 12.0;
pub fn material(corner_radius: f32, blur_radius: f32, child: impl IntoElement) -> Material {
let radius = AbsoluteLength::from(px(corner_radius));
Material {
corners: Corners {
top_left: radius,
top_right: radius,
bottom_right: radius,
bottom_left: radius,
},
blur_radius,
glass: false,
tint: None,
blur_override: None,
child: child.into_any_element(),
}
}
pub trait Glass: Styled + IntoElement + Sized {
fn material(mut self, blur_radius: f32) -> Material {
Material {
corners: corners_of(&mut self),
blur_radius,
glass: false,
tint: None,
blur_override: None,
child: self.into_any_element(),
}
}
fn glass_effect(mut self) -> Material {
let corners = corners_of(&mut self);
self.style().background = None;
Material {
corners,
blur_radius: 0.0,
glass: true,
tint: None,
blur_override: None,
child: self.into_any_element(),
}
}
}
fn corners_of(styled: &mut impl Styled) -> Corners<AbsoluteLength> {
let square = AbsoluteLength::from(px(0.0));
let radii = &styled.style().corner_radii;
Corners {
top_left: radii.top_left.unwrap_or(square),
top_right: radii.top_right.unwrap_or(square),
bottom_right: radii.bottom_right.unwrap_or(square),
bottom_left: radii.bottom_left.unwrap_or(square),
}
}
impl<E: Styled + IntoElement> Glass for E {}
pub struct Material {
tint: Option<gpui::Hsla>,
blur_override: Option<f32>,
corners: Corners<AbsoluteLength>,
blur_radius: f32,
glass: bool,
child: AnyElement,
}
const LENSED: bool = cfg!(any(target_os = "macos", target_family = "wasm"));
pub fn lensed(theme: &Theme) -> bool {
LENSED && theme.is_glass()
}
impl Material {
pub fn tint(mut self, color: gpui::Hsla) -> Self {
self.tint = Some(color);
self
}
pub fn blurred(mut self, sigma: f32) -> Self {
self.blur_override = Some(sigma);
self
}
fn corners(&self, rem: Pixels) -> Corners<Pixels> {
Corners {
top_left: self.corners.top_left.to_pixels(rem),
top_right: self.corners.top_right.to_pixels(rem),
bottom_right: self.corners.bottom_right.to_pixels(rem),
bottom_left: self.corners.bottom_left.to_pixels(rem),
}
}
}
impl Element for Material {
type RequestLayoutState = ();
type PrepaintState = ();
fn id(&self) -> Option<gpui::ElementId> {
None
}
fn source_location(&self) -> Option<&'static core::panic::Location<'static>> {
None
}
fn request_layout(
&mut self,
_id: Option<&GlobalElementId>,
_inspector_id: Option<&InspectorElementId>,
window: &mut Window,
cx: &mut App,
) -> (LayoutId, ()) {
(self.child.request_layout(window, cx), ())
}
fn prepaint(
&mut self,
_id: Option<&GlobalElementId>,
_inspector_id: Option<&InspectorElementId>,
_bounds: Bounds<Pixels>,
_request_layout: &mut Self::RequestLayoutState,
window: &mut Window,
cx: &mut App,
) {
self.child.prepaint(window, cx);
}
fn paint(
&mut self,
_id: Option<&GlobalElementId>,
_inspector_id: Option<&InspectorElementId>,
bounds: Bounds<Pixels>,
_request_layout: &mut Self::RequestLayoutState,
_prepaint: &mut Self::PrepaintState,
window: &mut Window,
cx: &mut App,
) {
let theme = Theme::of(cx);
if self.glass && !lensed(theme) {
let corners = self.corners(window.rem_size());
window.paint_quad(fill(bounds, theme.glass_overlay()).corner_radii(corners));
if let Some(tint) = self.tint {
window.paint_quad(fill(bounds, tint).corner_radii(corners));
}
}
if theme.is_glass() {
let (bevel, tint) = if self.glass {
let extent = bounds.size.width.min(bounds.size.height);
(
Theme::glass_bevel(f32::from(extent)),
self.tint.unwrap_or_else(|| theme.glass_clear()),
)
} else {
(0.0, gpui::transparent_black())
};
let corners = self.corners(window.rem_size());
window.paint_layer(bounds, |window| {
window.paint_backdrop_blur(
bounds,
corners,
gpui::GlassEffect {
blur_radius: px(self.blur_override.unwrap_or(self.blur_radius)),
lens: px(bevel),
magnify: Theme::glass_magnify(),
dispersion: Theme::glass_dispersion(),
tint,
},
);
self.child.paint(window, cx);
});
} else {
self.child.paint(window, cx);
}
}
}
impl IntoElement for Material {
type Element = Self;
fn into_element(self) -> Self::Element {
self
}
}
pub fn layered(child: impl IntoElement) -> Layered {
Layered {
child: child.into_any_element(),
}
}
pub struct Layered {
child: AnyElement,
}
impl Element for Layered {
type RequestLayoutState = ();
type PrepaintState = ();
fn id(&self) -> Option<gpui::ElementId> {
None
}
fn source_location(&self) -> Option<&'static core::panic::Location<'static>> {
None
}
fn request_layout(
&mut self,
_id: Option<&GlobalElementId>,
_inspector_id: Option<&InspectorElementId>,
window: &mut Window,
cx: &mut App,
) -> (LayoutId, ()) {
(self.child.request_layout(window, cx), ())
}
fn prepaint(
&mut self,
_id: Option<&GlobalElementId>,
_inspector_id: Option<&InspectorElementId>,
_bounds: Bounds<Pixels>,
_request_layout: &mut Self::RequestLayoutState,
window: &mut Window,
cx: &mut App,
) {
self.child.prepaint(window, cx);
}
fn paint(
&mut self,
_id: Option<&GlobalElementId>,
_inspector_id: Option<&InspectorElementId>,
bounds: Bounds<Pixels>,
_request_layout: &mut Self::RequestLayoutState,
_prepaint: &mut Self::PrepaintState,
window: &mut Window,
cx: &mut App,
) {
window.paint_layer(bounds, |window| self.child.paint(window, cx));
}
}
impl IntoElement for Layered {
type Element = Self;
fn into_element(self) -> Self::Element {
self
}
}