iced_core/
theme.rs

1//! Use the built-in theme and styles.
2pub mod palette;
3
4pub use palette::Palette;
5
6use crate::Color;
7
8use std::borrow::Cow;
9use std::fmt;
10use std::sync::Arc;
11
12/// A built-in theme.
13#[derive(Debug, Clone, PartialEq)]
14pub enum Theme {
15    /// The built-in light variant.
16    Light,
17    /// The built-in dark variant.
18    Dark,
19    /// The built-in Dracula variant.
20    Dracula,
21    /// The built-in Nord variant.
22    Nord,
23    /// The built-in Solarized Light variant.
24    SolarizedLight,
25    /// The built-in Solarized Dark variant.
26    SolarizedDark,
27    /// The built-in Gruvbox Light variant.
28    GruvboxLight,
29    /// The built-in Gruvbox Dark variant.
30    GruvboxDark,
31    /// The built-in Catppuccin Latte variant.
32    CatppuccinLatte,
33    /// The built-in Catppuccin Frappé variant.
34    CatppuccinFrappe,
35    /// The built-in Catppuccin Macchiato variant.
36    CatppuccinMacchiato,
37    /// The built-in Catppuccin Mocha variant.
38    CatppuccinMocha,
39    /// The built-in Tokyo Night variant.
40    TokyoNight,
41    /// The built-in Tokyo Night Storm variant.
42    TokyoNightStorm,
43    /// The built-in Tokyo Night Light variant.
44    TokyoNightLight,
45    /// The built-in Kanagawa Wave variant.
46    KanagawaWave,
47    /// The built-in Kanagawa Dragon variant.
48    KanagawaDragon,
49    /// The built-in Kanagawa Lotus variant.
50    KanagawaLotus,
51    /// The built-in Moonfly variant.
52    Moonfly,
53    /// The built-in Nightfly variant.
54    Nightfly,
55    /// The built-in Oxocarbon variant.
56    Oxocarbon,
57    /// The built-in Ferra variant:
58    Ferra,
59    /// A [`Theme`] that uses a [`Custom`] palette.
60    Custom(Arc<Custom>),
61}
62
63impl Theme {
64    /// A list with all the defined themes.
65    pub const ALL: &'static [Self] = &[
66        Self::Light,
67        Self::Dark,
68        Self::Dracula,
69        Self::Nord,
70        Self::SolarizedLight,
71        Self::SolarizedDark,
72        Self::GruvboxLight,
73        Self::GruvboxDark,
74        Self::CatppuccinLatte,
75        Self::CatppuccinFrappe,
76        Self::CatppuccinMacchiato,
77        Self::CatppuccinMocha,
78        Self::TokyoNight,
79        Self::TokyoNightStorm,
80        Self::TokyoNightLight,
81        Self::KanagawaWave,
82        Self::KanagawaDragon,
83        Self::KanagawaLotus,
84        Self::Moonfly,
85        Self::Nightfly,
86        Self::Oxocarbon,
87        Self::Ferra,
88    ];
89
90    /// Creates a new custom [`Theme`] from the given [`Palette`].
91    pub fn custom(
92        name: impl Into<Cow<'static, str>>,
93        palette: Palette,
94    ) -> Self {
95        Self::custom_with_fn(name, palette, palette::Extended::generate)
96    }
97
98    /// Creates a new custom [`Theme`] from the given [`Palette`], with
99    /// a custom generator of a [`palette::Extended`].
100    pub fn custom_with_fn(
101        name: impl Into<Cow<'static, str>>,
102        palette: Palette,
103        generate: impl FnOnce(Palette) -> palette::Extended,
104    ) -> Self {
105        Self::Custom(Arc::new(Custom::with_fn(name, palette, generate)))
106    }
107
108    /// Returns the [`Palette`] of the [`Theme`].
109    pub fn palette(&self) -> Palette {
110        match self {
111            Self::Light => Palette::LIGHT,
112            Self::Dark => Palette::DARK,
113            Self::Dracula => Palette::DRACULA,
114            Self::Nord => Palette::NORD,
115            Self::SolarizedLight => Palette::SOLARIZED_LIGHT,
116            Self::SolarizedDark => Palette::SOLARIZED_DARK,
117            Self::GruvboxLight => Palette::GRUVBOX_LIGHT,
118            Self::GruvboxDark => Palette::GRUVBOX_DARK,
119            Self::CatppuccinLatte => Palette::CATPPUCCIN_LATTE,
120            Self::CatppuccinFrappe => Palette::CATPPUCCIN_FRAPPE,
121            Self::CatppuccinMacchiato => Palette::CATPPUCCIN_MACCHIATO,
122            Self::CatppuccinMocha => Palette::CATPPUCCIN_MOCHA,
123            Self::TokyoNight => Palette::TOKYO_NIGHT,
124            Self::TokyoNightStorm => Palette::TOKYO_NIGHT_STORM,
125            Self::TokyoNightLight => Palette::TOKYO_NIGHT_LIGHT,
126            Self::KanagawaWave => Palette::KANAGAWA_WAVE,
127            Self::KanagawaDragon => Palette::KANAGAWA_DRAGON,
128            Self::KanagawaLotus => Palette::KANAGAWA_LOTUS,
129            Self::Moonfly => Palette::MOONFLY,
130            Self::Nightfly => Palette::NIGHTFLY,
131            Self::Oxocarbon => Palette::OXOCARBON,
132            Self::Ferra => Palette::FERRA,
133            Self::Custom(custom) => custom.palette,
134        }
135    }
136
137    /// Returns the [`palette::Extended`] of the [`Theme`].
138    pub fn extended_palette(&self) -> &palette::Extended {
139        match self {
140            Self::Light => &palette::EXTENDED_LIGHT,
141            Self::Dark => &palette::EXTENDED_DARK,
142            Self::Dracula => &palette::EXTENDED_DRACULA,
143            Self::Nord => &palette::EXTENDED_NORD,
144            Self::SolarizedLight => &palette::EXTENDED_SOLARIZED_LIGHT,
145            Self::SolarizedDark => &palette::EXTENDED_SOLARIZED_DARK,
146            Self::GruvboxLight => &palette::EXTENDED_GRUVBOX_LIGHT,
147            Self::GruvboxDark => &palette::EXTENDED_GRUVBOX_DARK,
148            Self::CatppuccinLatte => &palette::EXTENDED_CATPPUCCIN_LATTE,
149            Self::CatppuccinFrappe => &palette::EXTENDED_CATPPUCCIN_FRAPPE,
150            Self::CatppuccinMacchiato => {
151                &palette::EXTENDED_CATPPUCCIN_MACCHIATO
152            }
153            Self::CatppuccinMocha => &palette::EXTENDED_CATPPUCCIN_MOCHA,
154            Self::TokyoNight => &palette::EXTENDED_TOKYO_NIGHT,
155            Self::TokyoNightStorm => &palette::EXTENDED_TOKYO_NIGHT_STORM,
156            Self::TokyoNightLight => &palette::EXTENDED_TOKYO_NIGHT_LIGHT,
157            Self::KanagawaWave => &palette::EXTENDED_KANAGAWA_WAVE,
158            Self::KanagawaDragon => &palette::EXTENDED_KANAGAWA_DRAGON,
159            Self::KanagawaLotus => &palette::EXTENDED_KANAGAWA_LOTUS,
160            Self::Moonfly => &palette::EXTENDED_MOONFLY,
161            Self::Nightfly => &palette::EXTENDED_NIGHTFLY,
162            Self::Oxocarbon => &palette::EXTENDED_OXOCARBON,
163            Self::Ferra => &palette::EXTENDED_FERRA,
164            Self::Custom(custom) => &custom.extended,
165        }
166    }
167}
168
169impl Default for Theme {
170    fn default() -> Self {
171        #[cfg(feature = "auto-detect-theme")]
172        {
173            use std::sync::LazyLock;
174
175            static DEFAULT: LazyLock<Theme> = LazyLock::new(|| {
176                match dark_light::detect()
177                    .unwrap_or(dark_light::Mode::Unspecified)
178                {
179                    dark_light::Mode::Dark => Theme::Dark,
180                    dark_light::Mode::Light | dark_light::Mode::Unspecified => {
181                        Theme::Light
182                    }
183                }
184            });
185
186            DEFAULT.clone()
187        }
188
189        #[cfg(not(feature = "auto-detect-theme"))]
190        Theme::Light
191    }
192}
193
194impl fmt::Display for Theme {
195    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
196        match self {
197            Self::Light => write!(f, "Light"),
198            Self::Dark => write!(f, "Dark"),
199            Self::Dracula => write!(f, "Dracula"),
200            Self::Nord => write!(f, "Nord"),
201            Self::SolarizedLight => write!(f, "Solarized Light"),
202            Self::SolarizedDark => write!(f, "Solarized Dark"),
203            Self::GruvboxLight => write!(f, "Gruvbox Light"),
204            Self::GruvboxDark => write!(f, "Gruvbox Dark"),
205            Self::CatppuccinLatte => write!(f, "Catppuccin Latte"),
206            Self::CatppuccinFrappe => write!(f, "Catppuccin Frappé"),
207            Self::CatppuccinMacchiato => write!(f, "Catppuccin Macchiato"),
208            Self::CatppuccinMocha => write!(f, "Catppuccin Mocha"),
209            Self::TokyoNight => write!(f, "Tokyo Night"),
210            Self::TokyoNightStorm => write!(f, "Tokyo Night Storm"),
211            Self::TokyoNightLight => write!(f, "Tokyo Night Light"),
212            Self::KanagawaWave => write!(f, "Kanagawa Wave"),
213            Self::KanagawaDragon => write!(f, "Kanagawa Dragon"),
214            Self::KanagawaLotus => write!(f, "Kanagawa Lotus"),
215            Self::Moonfly => write!(f, "Moonfly"),
216            Self::Nightfly => write!(f, "Nightfly"),
217            Self::Oxocarbon => write!(f, "Oxocarbon"),
218            Self::Ferra => write!(f, "Ferra"),
219            Self::Custom(custom) => custom.fmt(f),
220        }
221    }
222}
223
224/// A [`Theme`] with a customized [`Palette`].
225#[derive(Debug, Clone, PartialEq)]
226pub struct Custom {
227    name: Cow<'static, str>,
228    palette: Palette,
229    extended: palette::Extended,
230}
231
232impl Custom {
233    /// Creates a [`Custom`] theme from the given [`Palette`].
234    pub fn new(name: String, palette: Palette) -> Self {
235        Self::with_fn(name, palette, palette::Extended::generate)
236    }
237
238    /// Creates a [`Custom`] theme from the given [`Palette`] with
239    /// a custom generator of a [`palette::Extended`].
240    pub fn with_fn(
241        name: impl Into<Cow<'static, str>>,
242        palette: Palette,
243        generate: impl FnOnce(Palette) -> palette::Extended,
244    ) -> Self {
245        Self {
246            name: name.into(),
247            palette,
248            extended: generate(palette),
249        }
250    }
251}
252
253impl fmt::Display for Custom {
254    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
255        write!(f, "{}", self.name)
256    }
257}
258
259/// The base style of a theme.
260#[derive(Debug, Clone, Copy, PartialEq)]
261pub struct Style {
262    /// The background [`Color`] of the application.
263    pub background_color: Color,
264
265    /// The default text [`Color`] of the application.
266    pub text_color: Color,
267}
268
269/// The default blank style of a theme.
270pub trait Base {
271    /// Returns the default base [`Style`] of a theme.
272    fn base(&self) -> Style;
273
274    /// Returns the color [`Palette`] of the theme.
275    ///
276    /// This [`Palette`] may be used by the runtime for
277    /// debugging purposes; like displaying performance
278    /// metrics or devtools.
279    fn palette(&self) -> Option<Palette>;
280}
281
282impl Base for Theme {
283    fn base(&self) -> Style {
284        default(self)
285    }
286
287    fn palette(&self) -> Option<Palette> {
288        Some(self.palette())
289    }
290}
291
292/// The default [`Style`] of a built-in [`Theme`].
293pub fn default(theme: &Theme) -> Style {
294    let palette = theme.extended_palette();
295
296    Style {
297        background_color: palette.background.base.color,
298        text_color: palette.background.base.text,
299    }
300}