use std::fmt::Write;
use crate::fmt::horizontal_border;
use crate::terminal::UnicodeTerminalFrame;
#[derive(Debug)]
pub struct Legend<'a> {
title: &'a str,
items: Vec<String>,
size: tuinix::TerminalSize,
}
impl<'a> Legend<'a> {
pub fn new<I>(title: &'a str, items: I) -> Self
where
I: Iterator<Item = String>,
{
let items = items.collect::<Vec<_>>();
let rows = items.len() + 1; let border_cols = if title.is_empty() {
2 } else {
calculate_cols(title) + 4 };
let cols = std::iter::once(border_cols)
.chain(items.iter().map(|x| calculate_cols(x) + 1)) .max()
.expect("infallible");
let size = tuinix::TerminalSize::rows_cols(rows, cols);
Self { title, items, size }
}
pub fn render(&self, frame: &mut UnicodeTerminalFrame) -> std::fmt::Result {
let Some(position) = frame
.size()
.cols
.checked_sub(self.size.cols)
.map(tuinix::TerminalPosition::col)
.filter(|_| self.size.rows < frame.size().rows)
else {
return Ok(());
};
let mut subframe = UnicodeTerminalFrame::new(self.size);
for item in &self.items {
writeln!(subframe, "│{item}")?;
}
writeln!(
subframe,
"└{}─",
horizontal_border(self.title, self.size.cols - 2)
)?;
frame.draw(position, &subframe);
Ok(())
}
pub fn size(&self) -> tuinix::TerminalSize {
self.size
}
}
fn calculate_cols(s: &str) -> usize {
let mut frame = UnicodeTerminalFrame::new(tuinix::TerminalSize::rows_cols(1, usize::MAX));
let _ = frame.write_str(s);
frame.cursor().col
}