use std::cell::RefCell; use ruin_ui::{Color, TextFontFamily, TextWrap}; use crate::primitives::FontWeight; /// Partially-specified text style for context-based inheritance. /// /// Set on a container via `.text_style(...)`. All descendant `text()` nodes inherit /// any fields that are `Some`, falling back to their own defaults for fields that are `None`. /// Inner (closer) ancestors take precedence over outer ancestors. #[derive(Clone, Default)] pub struct PartialTextStyle { pub size: Option, pub color: Option, pub weight: Option, pub font_family: Option, pub wrap: Option, pub line_height: Option, } impl PartialTextStyle { /// Merge `other` on top of `self` — `other`'s `Some` fields win. fn merge_over(self, other: &PartialTextStyle) -> Self { Self { size: other.size.or(self.size), color: other.color.or(self.color), weight: other.weight.or(self.weight), font_family: other.font_family.clone().or(self.font_family), wrap: other.wrap.or(self.wrap), line_height: other.line_height.or(self.line_height), } } } thread_local! { static TEXT_STYLE_STACK: RefCell> = const { RefCell::new(Vec::new()) }; } /// Push a partial style onto the context stack. Must be paired with `pop_text_style`. pub(crate) fn push_text_style(style: PartialTextStyle) { TEXT_STYLE_STACK.with(|stack| stack.borrow_mut().push(style)); } /// Pop the top partial style from the context stack. pub(crate) fn pop_text_style() { TEXT_STYLE_STACK.with(|stack| { stack.borrow_mut().pop(); }); } /// Returns the effective `PartialTextStyle` at the current render position by merging /// all layers from outermost to innermost (innermost wins). pub(crate) fn current_text_style() -> PartialTextStyle { TEXT_STYLE_STACK.with(|stack| { stack .borrow() .iter() .fold(PartialTextStyle::default(), |acc, layer| { acc.merge_over(layer) }) }) }