Skip to main content

gpui/
colors.rs

1use crate::{App, Global, Window, WindowAppearance, rgb};
2use palette::rgb::Rgba;
3use std::ops::Deref;
4use std::sync::Arc;
5
6/// A pair of light and dark base palettes for application components to share.
7/// GPUI's built-in elements do not read this value automatically.
8///
9/// Choose a palette for a window with [`Colors::for_appearance`]. For one app-wide palette,
10/// call [`App::init_colors`] and read it with [`DefaultColors::default_colors`].
11///
12/// # Examples
13///
14/// ```
15/// use gpui::{colors::Colors, rgb};
16///
17/// let light = Colors::light();
18/// assert_eq!(light.background, rgb(0xffffff));
19///
20/// let dark = Colors::dark();
21/// assert_eq!(dark.text, rgb(0xffffff));
22/// ```
23#[derive(Clone, Debug)]
24pub struct Colors {
25    /// The default color for text.
26    pub text: Rgba,
27    /// The color for text on a [`Colors::selected`] background.
28    pub selected_text: Rgba,
29    /// The color of the window background.
30    pub background: Rgba,
31    /// The color for disabled controls and their text.
32    pub disabled: Rgba,
33    /// The color for selected items and highlighted controls.
34    pub selected: Rgba,
35    /// The color for borders around controls.
36    pub border: Rgba,
37    /// The color for dividers between items.
38    pub separator: Rgba,
39    /// The color for raised surfaces, such as cards and panels, drawn over [`Colors::background`].
40    pub container: Rgba,
41}
42
43impl Default for Colors {
44    /// Returns [`Colors::light`].
45    fn default() -> Self {
46        Self::light()
47    }
48}
49
50impl Colors {
51    /// Returns [`Colors::light`] or [`Colors::dark`] for the window's [`WindowAppearance`].
52    ///
53    /// The returned palette is a snapshot. Ask again after the window appearance changes.
54    pub fn for_appearance(window: &Window) -> Self {
55        match window.appearance() {
56            WindowAppearance::Light | WindowAppearance::VibrantLight => Self::light(),
57            WindowAppearance::Dark | WindowAppearance::VibrantDark => Self::dark(),
58        }
59    }
60
61    /// Returns the colors for dark appearances.
62    pub fn dark() -> Self {
63        Self {
64            text: rgb(0xffffff),
65            selected_text: rgb(0xffffff),
66            disabled: rgb(0x565656),
67            selected: rgb(0x2457ca),
68            background: rgb(0x222222),
69            border: rgb(0x000000),
70            separator: rgb(0xd9d9d9),
71            container: rgb(0x262626),
72        }
73    }
74
75    /// Returns the colors for light appearances.
76    ///
77    /// This is the set that [`Colors::default`] returns.
78    pub fn light() -> Self {
79        Self {
80            text: rgb(0x252525),
81            selected_text: rgb(0xffffff),
82            background: rgb(0xffffff),
83            disabled: rgb(0xb0b0b0),
84            selected: rgb(0x2a63d9),
85            border: rgb(0xd9d9d9),
86            separator: rgb(0xe6e6e6),
87            container: rgb(0xf4f5f5),
88        }
89    }
90
91    /// Returns the app-wide colors that [`App::init_colors`] set.
92    ///
93    /// # Panics
94    ///
95    /// Panics if [`App::init_colors`] has not been called.
96    pub fn get_global(cx: &App) -> &Arc<Colors> {
97        &cx.global::<GlobalColors>().0
98    }
99}
100
101/// The app-wide [`Colors`], stored as a global on the [`App`].
102///
103/// [`App::init_colors`] sets it. Read the colors through [`DefaultColors::default_colors`]
104/// or [`Colors::get_global`] rather than this type. It dereferences to the shared [`Colors`].
105#[derive(Clone, Debug)]
106pub struct GlobalColors(pub Arc<Colors>);
107
108impl Deref for GlobalColors {
109    type Target = Arc<Colors>;
110
111    fn deref(&self) -> &Self::Target {
112        &self.0
113    }
114}
115
116impl Global for GlobalColors {}
117
118/// Gives access to the app-wide [`Colors`] through `cx.default_colors()`.
119///
120/// [`App`] implements this trait. The colors exist only after [`App::init_colors`] runs.
121///
122/// # Panics
123///
124/// Calling [`DefaultColors::default_colors`] panics if [`App::init_colors`] has not been called.
125pub trait DefaultColors {
126    /// Returns the app-wide [`Colors`] that [`App::init_colors`] set.
127    fn default_colors(&self) -> &Arc<Colors>;
128}
129
130impl DefaultColors for App {
131    fn default_colors(&self) -> &Arc<Colors> {
132        &self.global::<GlobalColors>().0
133    }
134}
135
136/// Whether GPUI's base colors use the light or the dark set.
137///
138/// This is a two-value form of [`WindowAppearance`], which also has vibrant variants. The
139/// conversion from [`WindowAppearance`] maps each vibrant variant to its base set. Use
140/// [`Colors::light`] for `Light` and [`Colors::dark`] for `Dark`.
141#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
142pub enum DefaultAppearance {
143    /// Use the set of colors for light appearances.
144    #[default]
145    Light,
146    /// Use the set of colors for dark appearances.
147    Dark,
148}
149
150impl From<WindowAppearance> for DefaultAppearance {
151    fn from(appearance: WindowAppearance) -> Self {
152        match appearance {
153            WindowAppearance::Light | WindowAppearance::VibrantLight => Self::Light,
154            WindowAppearance::Dark | WindowAppearance::VibrantDark => Self::Dark,
155        }
156    }
157}