forked from reya/gpui-native-kit
feat: add native material backgrounds
This commit is contained in:
+89
-19
@@ -2,9 +2,10 @@ use crate::definition::ThemeDefinition;
|
||||
use crate::ramps::{AccentShades, Oklch, contrast_foreground, derive_shades, mix};
|
||||
use crate::system::SystemTheme;
|
||||
use crate::{
|
||||
Borders, ColorTokens, Elevations, Motion, Radius, Scrollbar, SizeTable, Spacing, ThemeVariant,
|
||||
Borders, ColorTokens, Elevations, MaterialTokens, Motion, Radius, Scrollbar, SizeTable,
|
||||
Spacing, ThemeVariant,
|
||||
};
|
||||
use gpui::px;
|
||||
use gpui::{WindowBackgroundAppearance, px};
|
||||
|
||||
/// The floor of a custom titlebar's height, in px at 100% scaling: the height
|
||||
/// macOS and Linux titlebars draw at regardless of the control scale.
|
||||
@@ -26,6 +27,8 @@ pub struct Ramps {
|
||||
pub struct ResolvedTheme {
|
||||
pub variant: ThemeVariant,
|
||||
pub colors: ColorTokens,
|
||||
/// The translucent paints over the window's native material.
|
||||
pub material: MaterialTokens,
|
||||
pub ramps: Ramps,
|
||||
pub radius: Radius,
|
||||
pub borders: Borders,
|
||||
@@ -41,6 +44,8 @@ pub struct ResolvedTheme {
|
||||
pub mono_font: &'static str,
|
||||
pub sizes: SizeTable,
|
||||
pub accessibility: crate::system::AccessibilityPreferences,
|
||||
/// The material a window should open with, after accessibility.
|
||||
pub window_background: WindowBackgroundAppearance,
|
||||
}
|
||||
|
||||
/// Overlay order (later wins): neutral base → system → preset definition.
|
||||
@@ -187,6 +192,15 @@ pub(crate) fn resolve(
|
||||
),
|
||||
};
|
||||
|
||||
// Reduced transparency forces the window opaque.
|
||||
let window_background = if system.accessibility.reduce_transparency {
|
||||
WindowBackgroundAppearance::Opaque
|
||||
} else {
|
||||
system
|
||||
.window_background
|
||||
.unwrap_or(WindowBackgroundAppearance::Opaque)
|
||||
};
|
||||
|
||||
let accessibility = system.accessibility;
|
||||
if accessibility.high_contrast {
|
||||
colors.border = mix(
|
||||
@@ -255,25 +269,35 @@ pub(crate) fn resolve(
|
||||
radius.sm = sm;
|
||||
}
|
||||
|
||||
let ramps = Ramps {
|
||||
primary: derive_shades(primary, colors.background, variant == ThemeVariant::Dark),
|
||||
secondary: derive_shades(
|
||||
colors.secondary,
|
||||
colors.background,
|
||||
variant == ThemeVariant::Dark,
|
||||
),
|
||||
destructive: derive_shades(
|
||||
destructive,
|
||||
colors.background,
|
||||
variant == ThemeVariant::Dark,
|
||||
),
|
||||
success: derive_shades(success, colors.background, variant == ThemeVariant::Dark),
|
||||
warning: derive_shades(warning, colors.background, variant == ThemeVariant::Dark),
|
||||
info: derive_shades(info, colors.background, variant == ThemeVariant::Dark),
|
||||
};
|
||||
|
||||
let material = MaterialTokens::derive(
|
||||
&colors,
|
||||
ramps.primary.base,
|
||||
variant,
|
||||
window_background != WindowBackgroundAppearance::Opaque,
|
||||
);
|
||||
|
||||
ResolvedTheme {
|
||||
variant,
|
||||
ramps: Ramps {
|
||||
primary: derive_shades(primary, colors.background, variant == ThemeVariant::Dark),
|
||||
secondary: derive_shades(
|
||||
colors.secondary,
|
||||
colors.background,
|
||||
variant == ThemeVariant::Dark,
|
||||
),
|
||||
destructive: derive_shades(
|
||||
destructive,
|
||||
colors.background,
|
||||
variant == ThemeVariant::Dark,
|
||||
),
|
||||
success: derive_shades(success, colors.background, variant == ThemeVariant::Dark),
|
||||
warning: derive_shades(warning, colors.background, variant == ThemeVariant::Dark),
|
||||
info: derive_shades(info, colors.background, variant == ThemeVariant::Dark),
|
||||
},
|
||||
ramps,
|
||||
colors,
|
||||
material,
|
||||
radius,
|
||||
borders: Borders::for_platform(system.source, variant),
|
||||
spacing: Spacing {
|
||||
@@ -290,6 +314,7 @@ pub(crate) fn resolve(
|
||||
mono_font: mono_font(),
|
||||
sizes,
|
||||
accessibility,
|
||||
window_background,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -308,7 +333,7 @@ fn mono_font() -> &'static str {
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::system::{AccessibilityPreferences, PartialPalette, SourceKind};
|
||||
use gpui::{Rgba, rgb};
|
||||
use gpui::{Rgba, WindowBackgroundAppearance, rgb};
|
||||
|
||||
fn hsla(hex: u32) -> gpui::Hsla {
|
||||
gpui::Hsla::from(rgb(hex))
|
||||
@@ -335,6 +360,7 @@ mod tests {
|
||||
titlebar_height: None,
|
||||
root_font_size: None,
|
||||
accessibility: AccessibilityPreferences::default(),
|
||||
window_background: None,
|
||||
source: SourceKind::Macos,
|
||||
}
|
||||
}
|
||||
@@ -537,6 +563,50 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn the_platforms_window_material_resolves_into_the_theme() {
|
||||
let mut stated = system(ThemeVariant::Light, PartialPalette::default(), None);
|
||||
stated.window_background = Some(WindowBackgroundAppearance::MicaBackdrop);
|
||||
let resolved = resolve(&stated, None, None);
|
||||
|
||||
assert_eq!(
|
||||
resolved.window_background,
|
||||
WindowBackgroundAppearance::MicaBackdrop
|
||||
);
|
||||
// Material surfaces stay translucent over the stated backdrop.
|
||||
assert!(resolved.material.background.a < resolved.colors.background.a);
|
||||
assert!(resolved.material.selection.a < 1.0);
|
||||
|
||||
let unstated = resolve(
|
||||
&system(ThemeVariant::Light, PartialPalette::default(), None),
|
||||
None,
|
||||
None,
|
||||
);
|
||||
assert_eq!(
|
||||
unstated.window_background,
|
||||
WindowBackgroundAppearance::Opaque
|
||||
);
|
||||
assert_eq!(unstated.material.background, unstated.colors.background);
|
||||
assert_eq!(unstated.material.hover, unstated.colors.muted);
|
||||
assert_eq!(unstated.material.selection, unstated.ramps.primary.base);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn reduced_transparency_forces_an_opaque_window_and_material() {
|
||||
let mut stated = system(ThemeVariant::Dark, PartialPalette::default(), None);
|
||||
stated.window_background = Some(WindowBackgroundAppearance::Blurred);
|
||||
stated.accessibility.reduce_transparency = true;
|
||||
let resolved = resolve(&stated, None, None);
|
||||
|
||||
assert_eq!(
|
||||
resolved.window_background,
|
||||
WindowBackgroundAppearance::Opaque
|
||||
);
|
||||
assert_eq!(resolved.material.background, resolved.colors.background);
|
||||
assert_eq!(resolved.material.hover, resolved.colors.muted);
|
||||
assert_eq!(resolved.material.selection, resolved.ramps.primary.base);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn overlay_is_translucent_and_overridable() {
|
||||
let light = resolve(
|
||||
|
||||
Reference in New Issue
Block a user