theme.rs

  1#![deny(missing_docs)]
  2
  3//! # Theme
  4//!
  5//! This crate provides the theme system for Zed.
  6//!
  7//! ## Overview
  8//!
  9//! A theme is a collection of colors used to build a consistent appearance for UI components across the application.
 10
 11mod default_colors;
 12mod fallback_themes;
 13mod font_family_cache;
 14mod registry;
 15mod scale;
 16mod schema;
 17mod settings;
 18mod styles;
 19
 20use std::sync::Arc;
 21
 22use ::settings::{Settings, SettingsStore};
 23pub use default_colors::*;
 24pub use font_family_cache::*;
 25pub use registry::*;
 26pub use scale::*;
 27pub use schema::*;
 28pub use settings::*;
 29pub use styles::*;
 30
 31use gpui::{
 32    px, AppContext, AssetSource, Hsla, Pixels, SharedString, WindowAppearance,
 33    WindowBackgroundAppearance,
 34};
 35use serde::Deserialize;
 36
 37/// Defines window border radius for platforms that use client side decorations.
 38pub const CLIENT_SIDE_DECORATION_ROUNDING: Pixels = px(10.0);
 39/// Defines window shadow size for platforms that use client side decorations.
 40pub const CLIENT_SIDE_DECORATION_SHADOW: Pixels = px(10.0);
 41
 42/// The appearance of the theme.
 43#[derive(Debug, PartialEq, Clone, Copy, Deserialize)]
 44pub enum Appearance {
 45    /// A light appearance.
 46    Light,
 47    /// A dark appearance.
 48    Dark,
 49}
 50
 51impl Appearance {
 52    /// Returns whether the appearance is light.
 53    pub fn is_light(&self) -> bool {
 54        match self {
 55            Self::Light => true,
 56            Self::Dark => false,
 57        }
 58    }
 59}
 60
 61impl From<WindowAppearance> for Appearance {
 62    fn from(value: WindowAppearance) -> Self {
 63        match value {
 64            WindowAppearance::Dark | WindowAppearance::VibrantDark => Self::Dark,
 65            WindowAppearance::Light | WindowAppearance::VibrantLight => Self::Light,
 66        }
 67    }
 68}
 69
 70/// Which themes should be loaded. This is used primarlily for testing.
 71pub enum LoadThemes {
 72    /// Only load the base theme.
 73    ///
 74    /// No user themes will be loaded.
 75    JustBase,
 76
 77    /// Load all of the built-in themes.
 78    All(Box<dyn AssetSource>),
 79}
 80
 81/// Initialize the theme system.
 82pub fn init(themes_to_load: LoadThemes, cx: &mut AppContext) {
 83    let (assets, load_user_themes) = match themes_to_load {
 84        LoadThemes::JustBase => (Box::new(()) as Box<dyn AssetSource>, false),
 85        LoadThemes::All(assets) => (assets, true),
 86    };
 87    ThemeRegistry::set_global(assets, cx);
 88
 89    if load_user_themes {
 90        ThemeRegistry::global(cx).load_bundled_themes();
 91    }
 92
 93    ThemeSettings::register(cx);
 94    FontFamilyCache::init_global(cx);
 95
 96    let mut prev_buffer_font_size = ThemeSettings::get_global(cx).buffer_font_size;
 97    cx.observe_global::<SettingsStore>(move |cx| {
 98        let buffer_font_size = ThemeSettings::get_global(cx).buffer_font_size;
 99        if buffer_font_size != prev_buffer_font_size {
100            prev_buffer_font_size = buffer_font_size;
101            reset_buffer_font_size(cx);
102        }
103    })
104    .detach();
105}
106
107/// Implementing this trait allows accessing the active theme.
108pub trait ActiveTheme {
109    /// Returns the active theme.
110    fn theme(&self) -> &Arc<Theme>;
111}
112
113impl ActiveTheme for AppContext {
114    fn theme(&self) -> &Arc<Theme> {
115        &ThemeSettings::get_global(self).active_theme
116    }
117}
118
119/// A theme family is a grouping of themes under a single name.
120///
121/// For example, the "One" theme family contains the "One Light" and "One Dark" themes.
122///
123/// It can also be used to package themes with many variants.
124///
125/// For example, the "Atelier" theme family contains "Cave", "Dune", "Estuary", "Forest", "Heath", etc.
126pub struct ThemeFamily {
127    /// The unique identifier for the theme family.
128    pub id: String,
129    /// The name of the theme family. This will be displayed in the UI, such as when adding or removing a theme family.
130    pub name: SharedString,
131    /// The author of the theme family.
132    pub author: SharedString,
133    /// The [Theme]s in the family.
134    pub themes: Vec<Theme>,
135    /// The color scales used by the themes in the family.
136    /// Note: This will be removed in the future.
137    pub scales: ColorScales,
138}
139
140impl ThemeFamily {}
141
142/// A theme is the primary mechanism for defining the appearance of the UI.
143#[derive(Clone, PartialEq)]
144pub struct Theme {
145    /// The unique identifier for the theme.
146    pub id: String,
147    /// The name of the theme.
148    pub name: SharedString,
149    /// The appearance of the theme (light or dark).
150    pub appearance: Appearance,
151    /// The colors and other styles for the theme.
152    pub styles: ThemeStyles,
153}
154
155impl Theme {
156    /// Returns the [`SystemColors`] for the theme.
157    #[inline(always)]
158    pub fn system(&self) -> &SystemColors {
159        &self.styles.system
160    }
161
162    /// Returns the [`AccentColors`] for the theme.
163    #[inline(always)]
164    pub fn accents(&self) -> &AccentColors {
165        &self.styles.accents
166    }
167
168    /// Returns the [`PlayerColors`] for the theme.
169    #[inline(always)]
170    pub fn players(&self) -> &PlayerColors {
171        &self.styles.player
172    }
173
174    /// Returns the [`ThemeColors`] for the theme.
175    #[inline(always)]
176    pub fn colors(&self) -> &ThemeColors {
177        &self.styles.colors
178    }
179
180    /// Returns the [`SyntaxTheme`] for the theme.
181    #[inline(always)]
182    pub fn syntax(&self) -> &Arc<SyntaxTheme> {
183        &self.styles.syntax
184    }
185
186    /// Returns the [`StatusColors`] for the theme.
187    #[inline(always)]
188    pub fn status(&self) -> &StatusColors {
189        &self.styles.status
190    }
191
192    /// Returns the color for the syntax node with the given name.
193    #[inline(always)]
194    pub fn syntax_color(&self, name: &str) -> Hsla {
195        self.syntax().color(name)
196    }
197
198    /// Returns the [`Appearance`] for the theme.
199    #[inline(always)]
200    pub fn appearance(&self) -> Appearance {
201        self.appearance
202    }
203
204    /// Returns the [`WindowBackgroundAppearance`] for the theme.
205    #[inline(always)]
206    pub fn window_background_appearance(&self) -> WindowBackgroundAppearance {
207        self.styles.window_background_appearance
208    }
209}
210
211/// Compounds a color with an alpha value.
212/// TODO: Replace this with a method on Hsla.
213pub fn color_alpha(color: Hsla, alpha: f32) -> Hsla {
214    let mut color = color;
215    color.a = alpha;
216    color
217}