use crate::view::accessibility::AccessNode;
use crate::view::context::ElementContext;
use crate::view::element::Element;
use crate::view::style::Style;
use crate::view::styled::Styled;
use crate::view::text_layout::TextLeaf;
use crate::gpu::TextRun;
use std::rc::Rc;
use taffy::NodeId;
pub struct Text {
content: Rc<str>,
runs: Rc<[TextRun]>,
style: Style,
monospace: bool,
node: Option<NodeId>,
leaf: Option<TextLeaf>,
}
pub fn text(content: impl Into<String>) -> Text {
Text::new(content)
}
pub fn styled_text(content: impl Into<String>, runs: Vec<TextRun>) -> Text {
let mut text = Text::new(content);
text.runs = Rc::from(runs);
text
}
impl Text {
pub fn new(content: impl Into<String>) -> Self {
let content: String = content.into();
Self {
content: Rc::from(content),
runs: Rc::from([]),
style: Style::default(),
monospace: false,
node: None,
leaf: None,
}
}
pub fn monospace(mut self) -> Self {
self.monospace = true;
self
}
}
impl Styled for Text {
fn style(&mut self) -> &mut Style {
&mut self.style
}
}
impl Element for Text {
fn request_layout(&mut self, cx: &mut ElementContext) -> NodeId {
let own_style = self.style.clone();
let leaf = cx.with_text_style(&own_style, |cx| {
let inherited = cx.text_style();
let decorated = inherited.bold || inherited.italic || inherited.underline || inherited.strike;
let runs = if self.runs.is_empty() && decorated {
Rc::from([TextRun {
length: self.content.len(),
color: None,
bold: inherited.bold,
italic: inherited.italic,
underline: inherited.underline,
strikethrough: inherited.strike,
..TextRun::default()
}])
} else {
self.runs.clone()
};
TextLeaf {
content: self.content.clone(),
runs,
font_size: inherited.size.0,
line_height: inherited.line_height(),
monospace: self.monospace || inherited.mono,
family: None,
wrap: inherited.wrap,
traits: inherited.traits,
}
});
let mut layout_style = self.style.clone();
layout_style.flex_shrink = layout_style.flex_shrink.or(Some(if leaf.wrap { 1.0 } else { 0.0 }));
let node = cx.request_text_node(&layout_style, leaf.clone());
self.node = Some(node);
self.leaf = Some(leaf);
node
}
fn prepaint(&mut self, cx: &mut ElementContext) {
if let (true, Some(node)) = (cx.accessibility_enabled(), self.node) {
let bounds = cx.node_bounds(node);
cx.register_access(AccessNode {
role: accesskit::Role::Label,
label: Some(self.content.clone()),
value: None,
bounds,
focus: None,
clickable: false,
});
}
}
fn paint(&mut self, cx: &mut ElementContext) {
let (Some(node), Some(leaf)) = (self.node, self.leaf.as_ref()) else { return };
let bounds = cx.node_bounds(node);
let shaped = cx.shape_leaf(leaf, Some(bounds.size.width.0));
let spec = self.style.text_color.unwrap_or(cx.text_style().color);
let color = cx.theme.resolve(spec);
cx.paint_text(&shaped, bounds.origin, color);
}
}