use crate::style::{Alignment, Color, FontStyle, FontWeight, SubtitleStyle, VerticalAlignment};
pub struct StyleInheritance;
impl StyleInheritance {
#[must_use]
pub fn resolve(parent: &SubtitleStyle, child: &SubtitleStyle) -> SubtitleStyle {
let def = SubtitleStyle::default();
SubtitleStyle {
font_size: if (child.font_size - def.font_size).abs() > f32::EPSILON {
child.font_size
} else {
parent.font_size
},
font_weight: if child.font_weight != def.font_weight {
child.font_weight
} else {
parent.font_weight
},
font_style: if child.font_style != def.font_style {
child.font_style
} else {
parent.font_style
},
primary_color: if child.primary_color != def.primary_color {
child.primary_color
} else {
parent.primary_color
},
secondary_color: if child.secondary_color != def.secondary_color {
child.secondary_color
} else {
parent.secondary_color
},
outline: if child.outline != def.outline {
child.outline
} else {
parent.outline
},
shadow: if child.shadow != def.shadow {
child.shadow
} else {
parent.shadow
},
alignment: if child.alignment != def.alignment {
child.alignment
} else {
parent.alignment
},
vertical_alignment: if child.vertical_alignment != def.vertical_alignment {
child.vertical_alignment
} else {
parent.vertical_alignment
},
position: if child.position != def.position {
child.position
} else {
parent.position
},
margin_left: if child.margin_left != def.margin_left {
child.margin_left
} else {
parent.margin_left
},
margin_right: if child.margin_right != def.margin_right {
child.margin_right
} else {
parent.margin_right
},
margin_top: if child.margin_top != def.margin_top {
child.margin_top
} else {
parent.margin_top
},
margin_bottom: if child.margin_bottom != def.margin_bottom {
child.margin_bottom
} else {
parent.margin_bottom
},
line_spacing: if (child.line_spacing - def.line_spacing).abs() > f32::EPSILON {
child.line_spacing
} else {
parent.line_spacing
},
word_wrap: if child.word_wrap != def.word_wrap {
child.word_wrap
} else {
parent.word_wrap
},
max_width: if child.max_width != def.max_width {
child.max_width
} else {
parent.max_width
},
background_color: if child.background_color != def.background_color {
child.background_color
} else {
parent.background_color
},
background_padding: if (child.background_padding - def.background_padding).abs()
> f32::EPSILON
{
child.background_padding
} else {
parent.background_padding
},
}
}
#[must_use]
pub fn resolve_chain(styles: &[SubtitleStyle]) -> SubtitleStyle {
match styles {
[] => SubtitleStyle::default(),
[single] => single.clone(),
[first, rest @ ..] => rest
.iter()
.fold(first.clone(), |acc, child| Self::resolve(&acc, child)),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_child_font_size_overrides_parent() {
let mut parent = SubtitleStyle::default();
parent.font_size = 24.0;
let mut child = SubtitleStyle::default();
child.font_size = 36.0;
let resolved = StyleInheritance::resolve(&parent, &child);
assert!((resolved.font_size - 36.0).abs() < f32::EPSILON);
}
#[test]
fn test_child_inherits_parent_font_size_when_default() {
let mut parent = SubtitleStyle::default();
parent.font_size = 48.0;
let child = SubtitleStyle::default();
let resolved = StyleInheritance::resolve(&parent, &child);
assert!((resolved.font_size - 48.0).abs() < f32::EPSILON);
}
#[test]
fn test_child_bold_overrides_parent_normal() {
let parent = SubtitleStyle::default(); let mut child = SubtitleStyle::default();
child.font_weight = FontWeight::Bold;
let resolved = StyleInheritance::resolve(&parent, &child);
assert_eq!(resolved.font_weight, FontWeight::Bold);
}
#[test]
fn test_child_inherits_parent_bold() {
let mut parent = SubtitleStyle::default();
parent.font_weight = FontWeight::Bold;
let child = SubtitleStyle::default();
let resolved = StyleInheritance::resolve(&parent, &child);
assert_eq!(resolved.font_weight, FontWeight::Bold);
}
#[test]
fn test_parent_and_child_same_returns_parent() {
let parent = SubtitleStyle::default();
let child = SubtitleStyle::default();
let resolved = StyleInheritance::resolve(&parent, &child);
assert_eq!(resolved, parent);
}
#[test]
fn test_resolve_chain_single() {
let mut s = SubtitleStyle::default();
s.font_size = 20.0;
let result = StyleInheritance::resolve_chain(&[s.clone()]);
assert!((result.font_size - 20.0).abs() < f32::EPSILON);
}
#[test]
fn test_resolve_chain_empty() {
let result = StyleInheritance::resolve_chain(&[]);
assert_eq!(result, SubtitleStyle::default());
}
#[test]
fn test_resolve_chain_three_layers() {
let mut layer0 = SubtitleStyle::default();
layer0.font_size = 20.0;
let mut layer1 = SubtitleStyle::default();
layer1.font_weight = FontWeight::Bold;
let mut layer2 = SubtitleStyle::default();
layer2.font_size = 32.0;
let resolved = StyleInheritance::resolve_chain(&[layer0, layer1, layer2]);
assert!((resolved.font_size - 32.0).abs() < f32::EPSILON);
assert_eq!(resolved.font_weight, FontWeight::Bold);
}
}