use unicode_segmentation::UnicodeSegmentation;
use unicode_width::UnicodeWidthStr;
use crate::render::{Buffer, Style};
use crate::style::{Color, ComputedStyle, Modifier};
pub(super) fn paint_text(
buf: &mut Buffer,
x: u16,
base_y: u16,
budget_right: u16,
text: &str,
style: Style,
) -> u16 {
if x >= budget_right || text.is_empty() {
return x;
}
let max_width = budget_right - x;
let text_width = UnicodeWidthStr::width(text).min(max_width as usize) as u16;
let _end = buf.set_stringn(x, base_y, text, max_width, style);
for cx in x..x.saturating_add(text_width) {
buf.clear_border_at(cx, base_y);
}
x + text_width
}
pub(super) fn pseudo_style(c: &ComputedStyle, overrides: &crate::ext::PresentationStyle) -> Style {
let mut style = style_from_computed(c);
if let Some(fg) = overrides.fg {
style = style.fg(fg);
}
if let Some(bg) = overrides.bg {
style = style.bg(bg);
}
style
}
pub(super) fn style_from_computed(c: &ComputedStyle) -> Style {
let mut style = Style::new();
if c.fg != Color::Reset {
style = style.fg(c.fg);
}
if c.bg != Color::Reset {
style = style.bg(c.bg);
}
let mods = c.modifiers
& (Modifier::BOLD | Modifier::ITALIC | Modifier::UNDERLINED | Modifier::CROSSED_OUT);
if !mods.is_empty() {
style = style.add_modifier(mods);
}
style
}
pub(super) fn glyph_style_from_computed(c: &ComputedStyle) -> Style {
let mut style = Style::new();
if c.fg != Color::Reset {
style = style.fg(c.fg);
}
let mods = c.modifiers
& (Modifier::BOLD | Modifier::ITALIC | Modifier::UNDERLINED | Modifier::CROSSED_OUT);
if !mods.is_empty() {
style = style.add_modifier(mods);
}
style
}
pub(super) fn advance_text_by_cells(text: &str, cells: u16) -> &str {
let mut consumed: u16 = 0;
let mut byte_pos: usize = 0;
for (idx, g) in text.grapheme_indices(true) {
if consumed >= cells {
byte_pos = idx;
return &text[byte_pos..];
}
let w = UnicodeWidthStr::width(g) as u16;
consumed = consumed.saturating_add(w);
byte_pos = idx + g.len();
}
&text[byte_pos..]
}
pub(super) fn paint_text_from(
buf: &mut Buffer,
x: i32,
y: u16,
clip_left: u16,
budget_right: u16,
text: &str,
style: Style,
) -> i32 {
let logical_end = x + UnicodeWidthStr::width(text) as i32;
if x >= i32::from(clip_left) {
let _ = paint_text(buf, x as u16, y, budget_right, text, style);
} else {
let skip = (i32::from(clip_left) - x).min(i32::from(u16::MAX)) as u16;
let rest = advance_text_by_cells(text, skip);
if !rest.is_empty() {
let _ = paint_text(buf, clip_left, y, budget_right, rest, style);
}
}
logical_end
}