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