#[cfg(not(alloc_frugal))]
use crate::widget::Widget;
#[cfg(not(alloc_frugal))]
pub(crate) fn apply_active_theme(widget: &mut dyn Widget) {
let kind_name = crate::widget::capability::factory_name_for_kind(widget.kind());
if kind_name.is_empty() {
log::debug!(
"theme: {:?} has no resolvable factory name; leaving its own style in place",
widget.kind()
);
return;
}
let Some(theme_style) = crate::theme::resolved_theme_style(kind_name) else {
return;
};
let mut style = widget.style().clone();
style.merge(&theme_style);
widget.set_style(style);
}
#[cfg(alloc_frugal)]
pub(crate) fn apply_active_theme(_widget: &mut dyn crate::widget::Widget) {}
#[cfg(all(test, not(alloc_frugal)))]
mod tests {
use super::*;
use crate::core::{Color, Rect};
use crate::theme::{self, global_theme_manager, AppearanceMode};
fn guard() -> std::sync::MutexGuard<'static, ()> {
theme::theme_test_guard()
}
#[test]
fn a_widget_with_no_style_gets_the_theme() {
let _guard = guard();
let mut manager = global_theme_manager();
assert!(manager.set_appearance(AppearanceMode::Light));
drop(manager);
let primary = global_theme_manager().current_theme().expect("active").colors.primary;
let mut button = crate::widget::Button::new("ok".to_string(), Rect::new(0, 0, 10, 10));
assert_eq!(button.style().background_color, None, "before: unset");
apply_active_theme(&mut button);
assert_eq!(
button.style().background_color,
Some(primary),
"a button's fill must come from the theme's primary token"
);
}
#[test]
fn an_explicit_style_is_not_overwritten() {
let _guard = guard();
let explicit = Color::rgb(1, 2, 3);
let mut button = crate::widget::Button::new("ok".to_string(), Rect::new(0, 0, 10, 10));
button.set_background_color(Some(explicit));
apply_active_theme(&mut button);
assert_eq!(
button.style().background_color,
Some(explicit),
"the theme must not replace a colour the caller set"
);
}
#[test]
fn switching_appearance_changes_what_a_new_control_gets() {
let _guard = guard();
{
let mut manager = global_theme_manager();
assert!(manager.set_appearance(AppearanceMode::Light));
}
let mut light = crate::widget::Button::new("ok".to_string(), Rect::new(0, 0, 10, 10));
apply_active_theme(&mut light);
{
let mut manager = global_theme_manager();
assert!(manager.set_appearance(AppearanceMode::Dark));
}
let mut dark = crate::widget::Button::new("ok".to_string(), Rect::new(0, 0, 10, 10));
apply_active_theme(&mut dark);
assert_ne!(
light.style().background_color,
dark.style().background_color,
"a light and a dark theme must fill a button differently"
);
global_theme_manager().set_appearance(AppearanceMode::Light);
}
#[test]
fn a_high_contrast_override_reaches_a_new_control() {
use crate::style::HighContrastMode;
let _guard = guard();
global_theme_manager().set_high_contrast(HighContrastMode::WhiteOnBlack);
let mut button = crate::widget::Button::new("ok".to_string(), Rect::new(0, 0, 10, 10));
apply_active_theme(&mut button);
assert_eq!(button.style().background_color, Some(Color::BLACK));
assert_eq!(button.style().text_color, Some(Color::WHITE));
global_theme_manager().set_high_contrast(HighContrastMode::None);
}
#[test]
fn different_kinds_get_different_treatments() {
let _guard = guard();
{
let mut manager = global_theme_manager();
assert!(manager.set_appearance(AppearanceMode::Light));
}
let mut button = crate::widget::Button::new("ok".to_string(), Rect::new(0, 0, 10, 10));
let mut label = crate::widget::Label::new("hi".to_string(), Rect::new(0, 0, 10, 10));
apply_active_theme(&mut button);
apply_active_theme(&mut label);
assert_ne!(
button.style().background_color,
label.style().background_color,
"a filled action and a plain label must not share a background"
);
}
}