egui_themes/
lib.rs

1#[derive(Debug, Default)]
2pub enum State {
3    Latte,
4    #[default]
5    Frappe,
6    Macchiato,
7    Mocha,
8}
9
10#[derive(Debug, Default)]
11pub struct StateMachine {
12    state: State,
13    theme: Theme,
14    is_latte: bool, // Used for setting ctx.set_visuals light or dark mode
15}
16
17impl StateMachine {
18    pub fn new() -> Self {
19        Self::default()
20    }
21
22    pub fn set_theme(&mut self, ctx: &egui::Context, theme: &Theme) {
23        StateMachine::update_theme(self, ctx, theme);
24    }
25
26    pub fn rotate_theme(&mut self, ctx: &egui::Context) {
27        match self.state {
28            State::Latte => {
29                self.theme = FRAPPE;
30                self.state = State::Frappe;
31                self.is_latte = false;
32            }
33            State::Frappe => {
34                self.theme = MACCHIATO;
35                self.state = State::Macchiato;
36                self.is_latte = false;
37            }
38            State::Macchiato => {
39                self.theme = MOCHA;
40                self.state = State::Mocha;
41                self.is_latte = false;
42            }
43            State::Mocha => {
44                self.theme = LATTE;
45                self.state = State::Latte;
46                self.is_latte = true;
47            }
48        }
49        StateMachine::update_theme(self, ctx, &self.theme);
50    }
51
52    fn update_theme(&self, ctx: &egui::Context, theme: &Theme) {
53        ctx.set_visuals(egui::Visuals {
54            dark_mode: if self.is_latte { false } else { true },
55            override_text_color: Some(theme.text),
56            widgets: egui::style::Widgets {
57                noninteractive: egui::style::WidgetVisuals {
58                    bg_fill: theme.base,
59                    weak_bg_fill: theme.base,
60                    bg_stroke: egui::Stroke {
61                        color: theme.overlay1,
62                        width: 1.0,
63                    },
64                    rounding: egui::Rounding::ZERO,
65                    fg_stroke: egui::Stroke {
66                        color: theme.text,
67                        width: 1.0,
68                    },
69                    expansion: 0.0,
70                },
71                inactive: egui::style::WidgetVisuals {
72                    bg_fill: theme.surface0,
73                    weak_bg_fill: theme.surface0,
74                    bg_stroke: egui::Stroke {
75                        color: theme.overlay1,
76                        width: 1.0,
77                    },
78                    rounding: egui::Rounding::ZERO,
79                    fg_stroke: egui::Stroke {
80                        color: theme.text,
81                        width: 1.0,
82                    },
83                    expansion: 0.0,
84                },
85                hovered: egui::style::WidgetVisuals {
86                    bg_fill: theme.surface2,
87                    weak_bg_fill: theme.surface2,
88                    bg_stroke: egui::Stroke {
89                        color: theme.overlay1,
90                        width: 1.0,
91                    },
92                    rounding: egui::Rounding::ZERO, // egui::Rounding of highlight around button or label
93                    fg_stroke: egui::Stroke {
94                        color: theme.text,
95                        width: 1.0,
96                    },
97                    expansion: 0.0,
98                },
99                active: egui::style::WidgetVisuals {
100                    bg_fill: theme.surface1,
101                    weak_bg_fill: theme.surface1,
102                    bg_stroke: egui::Stroke {
103                        color: theme.overlay1,
104                        width: 1.0,
105                    },
106                    rounding: egui::Rounding::ZERO,
107                    fg_stroke: egui::Stroke {
108                        color: theme.text,
109                        width: 1.0,
110                    },
111                    expansion: 0.0,
112                },
113                open: egui::style::WidgetVisuals {
114                    bg_fill: theme.surface0,
115                    weak_bg_fill: theme.surface0,
116                    bg_stroke: egui::Stroke {
117                        color: theme.overlay1,
118                        width: 1.0,
119                    },
120                    rounding: egui::Rounding::ZERO,
121                    fg_stroke: egui::Stroke {
122                        color: theme.text,
123                        width: 1.0,
124                    },
125                    expansion: 0.0,
126                },
127            },
128            selection: egui::style::Selection {
129                bg_fill: theme
130                    .blue
131                    .linear_multiply(if self.is_latte { 0.4 } else { 0.2 }),
132                stroke: egui::Stroke {
133                    color: theme.overlay1,
134                    width: 1.0,
135                },
136            },
137            hyperlink_color: theme.rosewater,
138            faint_bg_color: theme.surface0,
139            extreme_bg_color: theme.crust,
140            code_bg_color: theme.mantle,
141            warn_fg_color: theme.peach,
142            error_fg_color: theme.maroon,
143            window_rounding: egui::Rounding::ZERO,
144            window_shadow: egui::epaint::Shadow {
145                color: theme.base,
146                offset: egui::Vec2 { x: 0.0, y: 0.0 },
147                blur: 0.0,
148                spread: 0.0,
149            },
150            window_fill: theme.base,
151            window_stroke: egui::Stroke {
152                color: theme.overlay1,
153                width: 1.0,
154            },
155            window_highlight_topmost: true,
156            menu_rounding: egui::Rounding::same(4.), // Menu dropdown and tooltip "on_hover_text" rounding
157            panel_fill: theme.base,
158            popup_shadow: egui::epaint::Shadow {
159                color: theme.base,
160                offset: egui::Vec2 { x: 0.0, y: 0.0 },
161                blur: 0.0,
162                spread: 0.0,
163            },
164            resize_corner_size: 0.0,
165            text_cursor: egui::style::TextCursorStyle {
166                stroke: egui::Stroke {
167                    width: 2.0,
168                    color: theme.overlay1,
169                },
170                preview: false,
171                blink: true,
172                on_duration: 0.5,
173                off_duration: 0.5,
174            },
175            clip_rect_margin: 0.0,
176            button_frame: true,
177            collapsing_header_frame: true,
178            indent_has_left_vline: true,
179            striped: true,
180            slider_trailing_fill: true,
181            handle_shape: egui::style::HandleShape::Circle,
182            interact_cursor: Some(egui::CursorIcon::Default),
183            image_loading_spinners: true,
184            numeric_color_space: egui::style::NumericColorSpace::Linear,
185        });
186    }
187}
188
189#[derive(Debug, Default)]
190pub struct Theme {
191    pub rosewater: egui::Color32,
192    pub flamingo: egui::Color32,
193    pub pink: egui::Color32,
194    pub mauve: egui::Color32,
195    pub red: egui::Color32,
196    pub maroon: egui::Color32,
197    pub peach: egui::Color32,
198    pub yellow: egui::Color32,
199    pub green: egui::Color32,
200    pub teal: egui::Color32,
201    pub sky: egui::Color32,
202    pub sapphire: egui::Color32,
203    pub blue: egui::Color32,
204    pub lavender: egui::Color32,
205    pub text: egui::Color32,
206    pub subtext1: egui::Color32,
207    pub subtext0: egui::Color32,
208    pub overlay2: egui::Color32,
209    pub overlay1: egui::Color32,
210    pub overlay0: egui::Color32,
211    pub surface2: egui::Color32,
212    pub surface1: egui::Color32,
213    pub surface0: egui::Color32,
214    pub base: egui::Color32,
215    pub mantle: egui::Color32,
216    pub crust: egui::Color32,
217}
218
219pub const LATTE: Theme = Theme {
220    rosewater: egui::Color32::from_rgb(220, 138, 120),
221    flamingo: egui::Color32::from_rgb(221, 120, 120),
222    pink: egui::Color32::from_rgb(234, 118, 203),
223    mauve: egui::Color32::from_rgb(136, 57, 239),
224    red: egui::Color32::from_rgb(210, 15, 57),
225    maroon: egui::Color32::from_rgb(230, 69, 83),
226    peach: egui::Color32::from_rgb(254, 100, 11),
227    yellow: egui::Color32::from_rgb(223, 142, 29),
228    green: egui::Color32::from_rgb(64, 160, 43),
229    teal: egui::Color32::from_rgb(23, 146, 153),
230    sky: egui::Color32::from_rgb(4, 165, 229),
231    sapphire: egui::Color32::from_rgb(32, 159, 181),
232    blue: egui::Color32::from_rgb(30, 102, 245),
233    lavender: egui::Color32::from_rgb(114, 135, 253),
234    text: egui::Color32::from_rgb(76, 79, 105),
235    subtext1: egui::Color32::from_rgb(92, 95, 119),
236    subtext0: egui::Color32::from_rgb(108, 111, 133),
237    overlay2: egui::Color32::from_rgb(124, 127, 147),
238    overlay1: egui::Color32::from_rgb(140, 143, 161),
239    overlay0: egui::Color32::from_rgb(156, 160, 176),
240    surface2: egui::Color32::from_rgb(172, 176, 190),
241    surface1: egui::Color32::from_rgb(188, 192, 204),
242    surface0: egui::Color32::from_rgb(204, 208, 218),
243    base: egui::Color32::from_rgb(239, 241, 245),
244    mantle: egui::Color32::from_rgb(230, 233, 239),
245    crust: egui::Color32::from_rgb(220, 224, 232),
246};
247
248pub const FRAPPE: Theme = Theme {
249    rosewater: egui::Color32::from_rgb(242, 213, 207),
250    flamingo: egui::Color32::from_rgb(238, 190, 190),
251    pink: egui::Color32::from_rgb(244, 184, 228),
252    mauve: egui::Color32::from_rgb(202, 158, 230),
253    red: egui::Color32::from_rgb(231, 130, 132),
254    maroon: egui::Color32::from_rgb(234, 153, 156),
255    peach: egui::Color32::from_rgb(239, 159, 118),
256    yellow: egui::Color32::from_rgb(229, 200, 144),
257    green: egui::Color32::from_rgb(166, 209, 137),
258    teal: egui::Color32::from_rgb(129, 200, 190),
259    sky: egui::Color32::from_rgb(153, 209, 219),
260    sapphire: egui::Color32::from_rgb(133, 193, 220),
261    blue: egui::Color32::from_rgb(140, 170, 238),
262    lavender: egui::Color32::from_rgb(186, 187, 241),
263    text: egui::Color32::from_rgb(198, 208, 245),
264    subtext1: egui::Color32::from_rgb(181, 191, 226),
265    subtext0: egui::Color32::from_rgb(165, 173, 206),
266    overlay2: egui::Color32::from_rgb(148, 156, 187),
267    overlay1: egui::Color32::from_rgb(131, 139, 167),
268    overlay0: egui::Color32::from_rgb(115, 121, 148),
269    surface2: egui::Color32::from_rgb(98, 104, 128),
270    surface1: egui::Color32::from_rgb(81, 87, 109),
271    surface0: egui::Color32::from_rgb(65, 69, 89),
272    base: egui::Color32::from_rgb(48, 52, 70),
273    mantle: egui::Color32::from_rgb(41, 44, 60),
274    crust: egui::Color32::from_rgb(35, 38, 52),
275};
276
277pub const MACCHIATO: Theme = Theme {
278    rosewater: egui::Color32::from_rgb(244, 219, 214),
279    flamingo: egui::Color32::from_rgb(240, 198, 198),
280    pink: egui::Color32::from_rgb(245, 189, 230),
281    mauve: egui::Color32::from_rgb(198, 160, 246),
282    red: egui::Color32::from_rgb(237, 135, 150),
283    maroon: egui::Color32::from_rgb(238, 153, 160),
284    peach: egui::Color32::from_rgb(245, 169, 127),
285    yellow: egui::Color32::from_rgb(238, 212, 159),
286    green: egui::Color32::from_rgb(166, 218, 149),
287    teal: egui::Color32::from_rgb(139, 213, 202),
288    sky: egui::Color32::from_rgb(145, 215, 227),
289    sapphire: egui::Color32::from_rgb(125, 196, 228),
290    blue: egui::Color32::from_rgb(138, 173, 244),
291    lavender: egui::Color32::from_rgb(183, 189, 248),
292    text: egui::Color32::from_rgb(202, 211, 245),
293    subtext1: egui::Color32::from_rgb(184, 192, 224),
294    subtext0: egui::Color32::from_rgb(165, 173, 203),
295    overlay2: egui::Color32::from_rgb(147, 154, 183),
296    overlay1: egui::Color32::from_rgb(128, 135, 162),
297    overlay0: egui::Color32::from_rgb(110, 115, 141),
298    surface2: egui::Color32::from_rgb(91, 96, 120),
299    surface1: egui::Color32::from_rgb(73, 77, 100),
300    surface0: egui::Color32::from_rgb(54, 58, 79),
301    base: egui::Color32::from_rgb(36, 39, 58),
302    mantle: egui::Color32::from_rgb(30, 32, 48),
303    crust: egui::Color32::from_rgb(24, 25, 38),
304};
305
306pub const MOCHA: Theme = Theme {
307    rosewater: egui::Color32::from_rgb(245, 224, 220),
308    flamingo: egui::Color32::from_rgb(242, 205, 205),
309    pink: egui::Color32::from_rgb(245, 194, 231),
310    mauve: egui::Color32::from_rgb(203, 166, 247),
311    red: egui::Color32::from_rgb(243, 139, 168),
312    maroon: egui::Color32::from_rgb(235, 160, 172),
313    peach: egui::Color32::from_rgb(250, 179, 135),
314    yellow: egui::Color32::from_rgb(249, 226, 175),
315    green: egui::Color32::from_rgb(166, 227, 161),
316    teal: egui::Color32::from_rgb(148, 226, 213),
317    sky: egui::Color32::from_rgb(137, 220, 235),
318    sapphire: egui::Color32::from_rgb(116, 199, 236),
319    blue: egui::Color32::from_rgb(137, 180, 250),
320    lavender: egui::Color32::from_rgb(180, 190, 254),
321    text: egui::Color32::from_rgb(205, 214, 244),
322    subtext1: egui::Color32::from_rgb(186, 194, 222),
323    subtext0: egui::Color32::from_rgb(166, 173, 200),
324    overlay2: egui::Color32::from_rgb(147, 153, 178),
325    overlay1: egui::Color32::from_rgb(127, 132, 156),
326    overlay0: egui::Color32::from_rgb(108, 112, 134),
327    surface2: egui::Color32::from_rgb(88, 91, 112),
328    surface1: egui::Color32::from_rgb(69, 71, 90),
329    surface0: egui::Color32::from_rgb(49, 50, 68),
330    base: egui::Color32::from_rgb(30, 30, 46),
331    mantle: egui::Color32::from_rgb(24, 24, 37),
332    crust: egui::Color32::from_rgb(17, 17, 27),
333};