Skip to content

Commit cfd8038

Browse files
authored
Feathers theme now uses ThemeToken(SmolStr) instread of &'static str (#20969)
Fixes: #20967 EIBTI!
1 parent 3eb5cfc commit cfd8038

File tree

6 files changed

+161
-139
lines changed

6 files changed

+161
-139
lines changed

crates/bevy_feathers/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ bevy_ui = { path = "../bevy_ui", version = "0.17.0-dev", features = [
3131
] }
3232
bevy_ui_render = { path = "../bevy_ui_render", version = "0.17.0-dev" }
3333
bevy_window = { path = "../bevy_window", version = "0.17.0-dev" }
34+
smol_str = { version = "0.2", default-features = false }
3435

3536
# other
3637
accesskit = "0.21"

crates/bevy_feathers/src/controls/slider.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -172,12 +172,12 @@ fn set_slider_styles(
172172
gradient: &mut BackgroundGradient,
173173
commands: &mut Commands,
174174
) {
175-
let bar_color = theme.color(match disabled {
175+
let bar_color = theme.color(&match disabled {
176176
true => tokens::SLIDER_BAR_DISABLED,
177177
false => tokens::SLIDER_BAR,
178178
});
179179

180-
let bg_color = theme.color(tokens::SLIDER_BG);
180+
let bg_color = theme.color(&tokens::SLIDER_BG);
181181

182182
let cursor_shape = match disabled {
183183
true => bevy_window::SystemCursorIcon::NotAllowed,

crates/bevy_feathers/src/dark_theme.rs

Lines changed: 45 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -9,117 +9,90 @@ use crate::theme::ThemeProps;
99
pub fn create_dark_theme() -> ThemeProps {
1010
ThemeProps {
1111
color: HashMap::from([
12-
(tokens::WINDOW_BG.into(), palette::GRAY_0),
12+
(tokens::WINDOW_BG, palette::GRAY_0),
1313
// Button
14-
(tokens::BUTTON_BG.into(), palette::GRAY_3),
14+
(tokens::BUTTON_BG, palette::GRAY_3),
15+
(tokens::BUTTON_BG_HOVER, palette::GRAY_3.lighter(0.05)),
16+
(tokens::BUTTON_BG_PRESSED, palette::GRAY_3.lighter(0.1)),
17+
(tokens::BUTTON_BG_DISABLED, palette::GRAY_2),
18+
(tokens::BUTTON_PRIMARY_BG, palette::ACCENT),
1519
(
16-
tokens::BUTTON_BG_HOVER.into(),
17-
palette::GRAY_3.lighter(0.05),
18-
),
19-
(
20-
tokens::BUTTON_BG_PRESSED.into(),
21-
palette::GRAY_3.lighter(0.1),
22-
),
23-
(tokens::BUTTON_BG_DISABLED.into(), palette::GRAY_2),
24-
(tokens::BUTTON_PRIMARY_BG.into(), palette::ACCENT),
25-
(
26-
tokens::BUTTON_PRIMARY_BG_HOVER.into(),
20+
tokens::BUTTON_PRIMARY_BG_HOVER,
2721
palette::ACCENT.lighter(0.05),
2822
),
2923
(
30-
tokens::BUTTON_PRIMARY_BG_PRESSED.into(),
24+
tokens::BUTTON_PRIMARY_BG_PRESSED,
3125
palette::ACCENT.lighter(0.1),
3226
),
33-
(tokens::BUTTON_PRIMARY_BG_DISABLED.into(), palette::GRAY_2),
34-
(tokens::BUTTON_TEXT.into(), palette::WHITE),
27+
(tokens::BUTTON_PRIMARY_BG_DISABLED, palette::GRAY_2),
28+
(tokens::BUTTON_TEXT, palette::WHITE),
29+
(tokens::BUTTON_TEXT_DISABLED, palette::WHITE.with_alpha(0.5)),
30+
(tokens::BUTTON_PRIMARY_TEXT, palette::WHITE),
3531
(
36-
tokens::BUTTON_TEXT_DISABLED.into(),
37-
palette::WHITE.with_alpha(0.5),
38-
),
39-
(tokens::BUTTON_PRIMARY_TEXT.into(), palette::WHITE),
40-
(
41-
tokens::BUTTON_PRIMARY_TEXT_DISABLED.into(),
32+
tokens::BUTTON_PRIMARY_TEXT_DISABLED,
4233
palette::WHITE.with_alpha(0.5),
4334
),
4435
// Slider
45-
(tokens::SLIDER_BG.into(), palette::GRAY_1),
46-
(tokens::SLIDER_BAR.into(), palette::ACCENT),
47-
(tokens::SLIDER_BAR_DISABLED.into(), palette::GRAY_2),
48-
(tokens::SLIDER_TEXT.into(), palette::WHITE),
49-
(
50-
tokens::SLIDER_TEXT_DISABLED.into(),
51-
palette::WHITE.with_alpha(0.5),
52-
),
36+
(tokens::SLIDER_BG, palette::GRAY_1),
37+
(tokens::SLIDER_BAR, palette::ACCENT),
38+
(tokens::SLIDER_BAR_DISABLED, palette::GRAY_2),
39+
(tokens::SLIDER_TEXT, palette::WHITE),
40+
(tokens::SLIDER_TEXT_DISABLED, palette::WHITE.with_alpha(0.5)),
5341
// Checkbox
54-
(tokens::CHECKBOX_BG.into(), palette::GRAY_3),
55-
(tokens::CHECKBOX_BG_CHECKED.into(), palette::ACCENT),
42+
(tokens::CHECKBOX_BG, palette::GRAY_3),
43+
(tokens::CHECKBOX_BG_CHECKED, palette::ACCENT),
5644
(
57-
tokens::CHECKBOX_BG_DISABLED.into(),
45+
tokens::CHECKBOX_BG_DISABLED,
5846
palette::GRAY_1.with_alpha(0.5),
5947
),
6048
(
61-
tokens::CHECKBOX_BG_CHECKED_DISABLED.into(),
49+
tokens::CHECKBOX_BG_CHECKED_DISABLED,
6250
palette::GRAY_3.with_alpha(0.5),
6351
),
64-
(tokens::CHECKBOX_BORDER.into(), palette::GRAY_3),
52+
(tokens::CHECKBOX_BORDER, palette::GRAY_3),
53+
(tokens::CHECKBOX_BORDER_HOVER, palette::GRAY_3.lighter(0.1)),
6554
(
66-
tokens::CHECKBOX_BORDER_HOVER.into(),
67-
palette::GRAY_3.lighter(0.1),
68-
),
69-
(
70-
tokens::CHECKBOX_BORDER_DISABLED.into(),
55+
tokens::CHECKBOX_BORDER_DISABLED,
7156
palette::GRAY_3.with_alpha(0.5),
7257
),
73-
(tokens::CHECKBOX_MARK.into(), palette::WHITE),
74-
(tokens::CHECKBOX_MARK_DISABLED.into(), palette::LIGHT_GRAY_2),
75-
(tokens::CHECKBOX_TEXT.into(), palette::LIGHT_GRAY_1),
58+
(tokens::CHECKBOX_MARK, palette::WHITE),
59+
(tokens::CHECKBOX_MARK_DISABLED, palette::LIGHT_GRAY_2),
60+
(tokens::CHECKBOX_TEXT, palette::LIGHT_GRAY_1),
7661
(
77-
tokens::CHECKBOX_TEXT_DISABLED.into(),
62+
tokens::CHECKBOX_TEXT_DISABLED,
7863
palette::LIGHT_GRAY_1.with_alpha(0.5),
7964
),
8065
// Radio
81-
(tokens::RADIO_BORDER.into(), palette::GRAY_3),
82-
(
83-
tokens::RADIO_BORDER_HOVER.into(),
84-
palette::GRAY_3.lighter(0.1),
85-
),
66+
(tokens::RADIO_BORDER, palette::GRAY_3),
67+
(tokens::RADIO_BORDER_HOVER, palette::GRAY_3.lighter(0.1)),
8668
(
87-
tokens::RADIO_BORDER_DISABLED.into(),
69+
tokens::RADIO_BORDER_DISABLED,
8870
palette::GRAY_3.with_alpha(0.5),
8971
),
90-
(tokens::RADIO_MARK.into(), palette::ACCENT),
91-
(
92-
tokens::RADIO_MARK_DISABLED.into(),
93-
palette::ACCENT.with_alpha(0.5),
94-
),
95-
(tokens::RADIO_TEXT.into(), palette::LIGHT_GRAY_1),
72+
(tokens::RADIO_MARK, palette::ACCENT),
73+
(tokens::RADIO_MARK_DISABLED, palette::ACCENT.with_alpha(0.5)),
74+
(tokens::RADIO_TEXT, palette::LIGHT_GRAY_1),
9675
(
97-
tokens::RADIO_TEXT_DISABLED.into(),
76+
tokens::RADIO_TEXT_DISABLED,
9877
palette::LIGHT_GRAY_1.with_alpha(0.5),
9978
),
10079
// Toggle Switch
101-
(tokens::SWITCH_BG.into(), palette::GRAY_3),
102-
(tokens::SWITCH_BG_CHECKED.into(), palette::ACCENT),
80+
(tokens::SWITCH_BG, palette::GRAY_3),
81+
(tokens::SWITCH_BG_CHECKED, palette::ACCENT),
82+
(tokens::SWITCH_BG_DISABLED, palette::GRAY_1.with_alpha(0.5)),
10383
(
104-
tokens::SWITCH_BG_DISABLED.into(),
105-
palette::GRAY_1.with_alpha(0.5),
106-
),
107-
(
108-
tokens::SWITCH_BG_CHECKED_DISABLED.into(),
84+
tokens::SWITCH_BG_CHECKED_DISABLED,
10985
palette::GRAY_3.with_alpha(0.5),
11086
),
111-
(tokens::SWITCH_BORDER.into(), palette::GRAY_3),
112-
(
113-
tokens::SWITCH_BORDER_HOVER.into(),
114-
palette::GRAY_3.lighter(0.1),
115-
),
87+
(tokens::SWITCH_BORDER, palette::GRAY_3),
88+
(tokens::SWITCH_BORDER_HOVER, palette::GRAY_3.lighter(0.1)),
11689
(
117-
tokens::SWITCH_BORDER_DISABLED.into(),
90+
tokens::SWITCH_BORDER_DISABLED,
11891
palette::GRAY_3.with_alpha(0.5),
11992
),
120-
(tokens::SWITCH_SLIDE.into(), palette::LIGHT_GRAY_2),
93+
(tokens::SWITCH_SLIDE, palette::LIGHT_GRAY_2),
12194
(
122-
tokens::SWITCH_SLIDE_DISABLED.into(),
95+
tokens::SWITCH_SLIDE_DISABLED,
12396
palette::LIGHT_GRAY_2.with_alpha(0.3),
12497
),
12598
]),

crates/bevy_feathers/src/theme.rs

Lines changed: 46 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,42 @@ use bevy_platform::collections::HashMap;
1616
use bevy_reflect::{prelude::ReflectDefault, Reflect};
1717
use bevy_text::TextColor;
1818
use bevy_ui::{BackgroundColor, BorderColor};
19+
use smol_str::SmolStr;
20+
21+
/// A design token for the theme. This serves as the lookup key for the theme properties.
22+
#[derive(Clone, PartialEq, Eq, Hash, Reflect)]
23+
pub struct ThemeToken(SmolStr);
24+
25+
impl ThemeToken {
26+
/// Construct a new [`ThemeToken`] from a [`SmolStr`].
27+
pub const fn new(text: SmolStr) -> Self {
28+
Self(text)
29+
}
30+
31+
/// Construct a new [`ThemeToken`] from a static string.
32+
pub const fn new_static(text: &'static str) -> Self {
33+
Self(SmolStr::new_static(text))
34+
}
35+
}
36+
37+
impl core::fmt::Display for ThemeToken {
38+
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
39+
write!(f, "{}", self.0)
40+
}
41+
}
42+
43+
impl core::fmt::Debug for ThemeToken {
44+
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
45+
write!(f, "ThemeToken({:?})", self.0)
46+
}
47+
}
1948

2049
/// A collection of properties that make up a theme.
2150
#[derive(Default, Clone, Reflect, Debug)]
2251
#[reflect(Default, Debug)]
2352
pub struct ThemeProps {
2453
/// Map of design tokens to colors.
25-
pub color: HashMap<String, Color>,
54+
pub color: HashMap<ThemeToken, Color>,
2655
// Other style property types to be added later.
2756
}
2857

@@ -34,7 +63,7 @@ pub struct UiTheme(pub ThemeProps);
3463
impl UiTheme {
3564
/// Lookup a color by design token. If the theme does not have an entry for that token,
3665
/// logs a warning and returns an error color.
37-
pub fn color<'a>(&self, token: &'a str) -> Color {
66+
pub fn color(&self, token: &ThemeToken) -> Color {
3867
let color = self.0.color.get(token);
3968
match color {
4069
Some(c) => *c,
@@ -47,34 +76,36 @@ impl UiTheme {
4776
}
4877

4978
/// Associate a design token with a given color.
50-
pub fn set_color(&mut self, token: impl Into<String>, color: Color) {
51-
self.0.color.insert(token.into(), color);
79+
pub fn set_color(&mut self, token: &str, color: Color) {
80+
self.0
81+
.color
82+
.insert(ThemeToken::new(SmolStr::new(token)), color);
5283
}
5384
}
5485

5586
/// Component which causes the background color of an entity to be set based on a theme color.
56-
#[derive(Component, Clone, Copy)]
87+
#[derive(Component, Clone)]
5788
#[require(BackgroundColor)]
5889
#[component(immutable)]
5990
#[derive(Reflect)]
6091
#[reflect(Component, Clone)]
61-
pub struct ThemeBackgroundColor(pub &'static str);
92+
pub struct ThemeBackgroundColor(pub ThemeToken);
6293

6394
/// Component which causes the border color of an entity to be set based on a theme color.
6495
/// Only supports setting all borders to the same color.
65-
#[derive(Component, Clone, Copy)]
96+
#[derive(Component, Clone)]
6697
#[require(BorderColor)]
6798
#[component(immutable)]
6899
#[derive(Reflect)]
69100
#[reflect(Component, Clone)]
70-
pub struct ThemeBorderColor(pub &'static str);
101+
pub struct ThemeBorderColor(pub ThemeToken);
71102

72103
/// Component which causes the inherited text color of an entity to be set based on a theme color.
73-
#[derive(Component, Clone, Copy)]
104+
#[derive(Component, Clone)]
74105
#[component(immutable)]
75106
#[derive(Reflect)]
76107
#[reflect(Component, Clone)]
77-
pub struct ThemeFontColor(pub &'static str);
108+
pub struct ThemeFontColor(pub ThemeToken);
78109

79110
/// A marker component that is used to indicate that the text entity wants to opt-in to using
80111
/// inherited text styles.
@@ -90,12 +121,12 @@ pub(crate) fn update_theme(
90121
if theme.is_changed() {
91122
// Update all background colors
92123
for (mut bg, theme_bg) in q_background.iter_mut() {
93-
bg.0 = theme.color(theme_bg.0);
124+
bg.0 = theme.color(&theme_bg.0);
94125
}
95126

96127
// Update all border colors
97128
for (mut border, theme_border) in q_border.iter_mut() {
98-
border.set_all(theme.color(theme_border.0));
129+
border.set_all(theme.color(&theme_border.0));
99130
}
100131
}
101132
}
@@ -110,7 +141,7 @@ pub(crate) fn on_changed_background(
110141
) {
111142
// Update background colors where the design token has changed.
112143
if let Ok((mut bg, theme_bg)) = q_background.get_mut(insert.entity) {
113-
bg.0 = theme.color(theme_bg.0);
144+
bg.0 = theme.color(&theme_bg.0);
114145
}
115146
}
116147

@@ -121,7 +152,7 @@ pub(crate) fn on_changed_border(
121152
) {
122153
// Update background colors where the design token has changed.
123154
if let Ok((mut border, theme_border)) = q_border.get_mut(insert.entity) {
124-
border.set_all(theme.color(theme_border.0));
155+
border.set_all(theme.color(&theme_border.0));
125156
}
126157
}
127158

@@ -134,7 +165,7 @@ pub(crate) fn on_changed_font_color(
134165
mut commands: Commands,
135166
) {
136167
if let Ok(token) = font_color.get(insert.entity) {
137-
let color = theme.color(token.0);
168+
let color = theme.color(&token.0);
138169
commands
139170
.entity(insert.entity)
140171
.insert(Propagate(TextColor(color)));

0 commit comments

Comments
 (0)