ori_core/text/
paragraph.rsuse std::{
fmt::Display,
hash::{Hash, Hasher},
};
use smallvec::SmallVec;
use smol_str::{format_smolstr, SmolStr};
use super::{FontAttributes, TextAlign, TextWrap};
#[derive(Clone, Debug, Default, PartialEq)]
pub struct Paragraph {
pub line_height: f32,
pub align: TextAlign,
pub wrap: TextWrap,
text: SmolStr,
segments: SmallVec<[Segment; 1]>,
}
impl Paragraph {
pub fn new(line_height: f32, align: TextAlign, wrap: TextWrap) -> Self {
Self {
line_height,
align,
wrap,
text: SmolStr::default(),
segments: SmallVec::new(),
}
}
pub fn clear(&mut self) {
self.text = SmolStr::default();
self.segments.clear();
}
pub fn set_text(&mut self, text: impl Display, attrs: FontAttributes) {
self.clear();
self.push_text(text, attrs);
}
pub fn push_text(&mut self, text: impl Display, attrs: FontAttributes) {
self.text = format_smolstr!("{}{}", self.text, text);
self.segments.push(Segment {
end: self.text.len(),
attrs,
});
}
pub fn with_text(mut self, text: impl Display, attrs: FontAttributes) -> Self {
self.push_text(text, attrs);
self
}
pub fn text(&self) -> &str {
&self.text
}
pub fn iter(&self) -> impl DoubleEndedIterator<Item = (&str, &FontAttributes)> {
self.segments.iter().map(|segment| {
let start = segment.end - self.text.len();
let end = segment.end;
let text = &self.text[start..end];
(text, &segment.attrs)
})
}
pub fn iter_mut(&mut self) -> impl DoubleEndedIterator<Item = (&str, &mut FontAttributes)> {
let text = &self.text;
self.segments.iter_mut().map(|segment| {
let start = segment.end - self.text.len();
let end = segment.end;
let text = &text[start..end];
(text, &mut segment.attrs)
})
}
}
impl Eq for Paragraph {}
impl Hash for Paragraph {
fn hash<H: Hasher>(&self, state: &mut H) {
self.line_height.to_bits().hash(state);
self.align.hash(state);
self.wrap.hash(state);
self.text.hash(state);
self.segments.hash(state);
}
}
#[derive(Clone, Debug, PartialEq, Hash)]
struct Segment {
end: usize,
attrs: FontAttributes,
}