#![allow(missing_docs)]
use bevy::prelude::*;
#[derive(Component, Default, Clone, Debug)]
pub struct InheritableFontStyles {
pub font: Option<Handle<Font>>,
pub font_size: Option<f32>,
pub color: Option<Color>,
}
impl InheritableFontStyles {
pub fn is_final(&self) -> bool {
self.font.is_some() && self.font_size.is_some() && self.color.is_some()
}
pub fn merge(&mut self, other: &InheritableFontStyles) {
if other.font.is_some() && self.font.is_none() {
self.font.clone_from(&other.font);
}
if other.font_size.is_some() && self.font_size.is_none() {
self.font_size = other.font_size;
}
if other.color.is_some() && self.color.is_none() {
self.color = other.color;
}
}
}
#[derive(Component)]
pub struct UseInheritedTextStyles;
pub(crate) fn update_text_styles(
mut query: Query<(Entity, &mut Text), With<UseInheritedTextStyles>>,
inherited: Query<Ref<InheritableFontStyles>>,
parents: Query<&Parent>,
) {
let inherited_changed = inherited.iter().any(|cmp| cmp.is_changed());
for (entity, mut text) in query.iter_mut() {
if text.is_changed() || inherited_changed {
let style = match compute_inherited_style(entity, &inherited, &parents) {
Some(value) => value,
None => continue,
};
let styles_changed = text.sections.iter().any(|section| {
section.style.font != style.font
|| section.style.font_size != style.font_size
|| section.style.color != style.color
});
if styles_changed {
for section in text.sections.iter_mut() {
section.style = style.clone();
}
}
}
}
}
fn compute_inherited_style(
entity: Entity,
inherited: &Query<Ref<InheritableFontStyles>, ()>,
parents: &Query<&Parent, ()>,
) -> Option<TextStyle> {
let mut styles = InheritableFontStyles::default();
let mut ancestor = entity;
loop {
if styles.is_final() {
break;
}
if let Ok(inherited_styles) = inherited.get(ancestor) {
styles.merge(inherited_styles.as_ref());
if styles.is_final() {
break;
}
}
if let Ok(parent) = parents.get(ancestor) {
ancestor = parent.get();
} else {
break;
}
}
let style = TextStyle {
font: styles.font.unwrap_or_default(),
font_size: styles.font_size.unwrap_or(12.),
color: styles.color.unwrap_or(Color::WHITE),
};
Some(style)
}