1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
//! Theme picker — a one-line drop-in for switching between the four
//! built-in themes. Saves every app from re-implementing the
//! `Select::strings`-over-name-strings boilerplate.
use egui::{Id, Response, Ui, Widget};
use crate::theme::BuiltInTheme;
use crate::Select;
/// A drop-in picker for the four built-in elegance themes.
///
/// Renders a small [`Select`](crate::Select) of the four built-in themes
/// and — by default — installs the chosen theme into the context each
/// frame. Bind it to a [`BuiltInTheme`] held anywhere in your app state.
///
/// ```no_run
/// # use elegance::{BuiltInTheme, ThemeSwitcher};
/// # egui::__run_test_ui(|ui| {
/// let mut theme = BuiltInTheme::Slate;
/// ui.add(ThemeSwitcher::new(&mut theme));
/// # });
/// ```
///
/// # Installation
///
/// By default the widget calls [`Theme::install`](crate::Theme::install) on
/// the selected theme on every frame. If your app already installs a
/// theme elsewhere (for instance from a larger preference store), call
/// [`ThemeSwitcher::auto_install`]`(false)` to suppress that.
#[must_use = "Add with `ui.add(...)`."]
pub struct ThemeSwitcher<'a> {
current: &'a mut BuiltInTheme,
id_salt: Id,
width: f32,
auto_install: bool,
}
impl<'a> std::fmt::Debug for ThemeSwitcher<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("ThemeSwitcher")
.field("current", &*self.current)
.field("id_salt", &self.id_salt)
.field("width", &self.width)
.field("auto_install", &self.auto_install)
.finish()
}
}
impl<'a> ThemeSwitcher<'a> {
/// Create a switcher bound to a mutable [`BuiltInTheme`] slot.
pub fn new(current: &'a mut BuiltInTheme) -> Self {
Self {
current,
id_salt: Id::new("elegance_theme_switcher"),
width: 110.0,
auto_install: true,
}
}
/// Override the id salt. Only needed if multiple switchers coexist
/// in the same UI.
pub fn id_salt(mut self, id_salt: impl std::hash::Hash) -> Self {
self.id_salt = Id::new(id_salt);
self
}
/// Override the switcher width in points. Default: `110.0`.
pub fn width(mut self, width: f32) -> Self {
self.width = width;
self
}
/// Whether to call [`Theme::install`](crate::Theme::install) on the
/// selected theme every frame. Default: `true`.
///
/// Set to `false` if the caller installs a theme elsewhere and just
/// wants the picker UI.
pub fn auto_install(mut self, auto_install: bool) -> Self {
self.auto_install = auto_install;
self
}
}
impl Widget for ThemeSwitcher<'_> {
fn ui(self, ui: &mut Ui) -> Response {
let Self {
current,
id_salt,
width,
auto_install,
} = self;
let options = BuiltInTheme::all().into_iter().map(|t| (t, t.label()));
// Reborrow so `current` remains usable after the Select is consumed,
// which lets us install the (possibly just-updated) theme below.
let response = ui.add(
Select::new(id_salt, &mut *current)
.options(options)
.width(width),
);
if auto_install {
current.theme().install(ui.ctx());
}
response
}
}