Files
ruin/lib/ruin_app/src/text_style.rs
2026-05-16 16:38:10 -04:00

64 lines
2.1 KiB
Rust

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<f32>,
pub color: Option<Color>,
pub weight: Option<FontWeight>,
pub font_family: Option<TextFontFamily>,
pub wrap: Option<TextWrap>,
pub line_height: Option<f32>,
}
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<Vec<PartialTextStyle>> = 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)
})
})
}