use super::{Alignment, Widget};
use crate::{ColorPair, Error, Result, Window};
use figlet_rs::FIGfont;
pub struct FigletText {
text: String,
rendered: String,
width: u16,
height: u16,
colors: Option<ColorPair>,
alignment: Alignment,
}
impl FigletText {
pub fn standard(text: impl Into<String>) -> Result<Self> {
let font = FIGfont::standard().map_err(|e| {
Error::widget_validation(format!("Failed to load standard font: {}", e))
})?;
Self::with_font(text, font)
}
pub fn with_font(text: impl Into<String>, font: FIGfont) -> Result<Self> {
let text = text.into();
let figure = font
.convert(text.as_str())
.ok_or_else(|| Error::widget_validation(format!("Failed to render text: {}", text)))?;
let rendered = figure.to_string();
let lines: Vec<&str> = rendered.lines().collect();
let height = lines.len() as u16;
let width = lines.iter().map(|line| line.len()).max().unwrap_or(0) as u16;
Ok(Self {
text,
rendered,
width,
height,
colors: None,
alignment: Alignment::Left,
})
}
pub fn with_color(mut self, colors: ColorPair) -> Self {
self.colors = Some(colors);
self
}
pub fn with_alignment(mut self, alignment: Alignment) -> Self {
self.alignment = alignment;
self
}
pub fn text(&self) -> &str {
&self.text
}
pub fn rendered(&self) -> &str {
&self.rendered
}
fn calculate_aligned_x(&self, line_length: u16, available_width: u16) -> u16 {
match self.alignment {
Alignment::Left => 0,
Alignment::Center => {
if line_length < available_width {
(available_width - line_length) / 2
} else {
0
}
}
Alignment::Right => {
if line_length < available_width {
available_width - line_length
} else {
0
}
}
}
}
}
impl Widget for FigletText {
fn draw(&self, window: &mut dyn Window) -> Result<()> {
let (window_width, _) = window.get_size();
for (row, line) in self.rendered.lines().enumerate() {
let line_len = line.chars().count() as u16;
let x_pos = self.calculate_aligned_x(line_len, window_width);
match self.colors {
Some(colors) => window.write_str_colored(row as u16, x_pos, line, colors)?,
None => window.write_str(row as u16, x_pos, line)?,
}
}
Ok(())
}
fn get_size(&self) -> (u16, u16) {
(self.width, self.height)
}
fn get_position(&self) -> (u16, u16) {
(0, 0) }
}