use crate::{ backend::Backend, buffer::Cell, layout::Rect, style::{Color, Modifier}, }; use std::io; pub struct RustboxBackend { rustbox: rustbox::RustBox, } impl RustboxBackend { pub fn new() -> Result { let rustbox = rustbox::RustBox::init(Default::default())?; Ok(RustboxBackend { rustbox }) } pub fn with_rustbox(instance: rustbox::RustBox) -> RustboxBackend { RustboxBackend { rustbox: instance } } pub fn rustbox(&self) -> &rustbox::RustBox { &self.rustbox } } impl Backend for RustboxBackend { fn draw<'a, I>(&mut self, content: I) -> Result<(), io::Error> where I: Iterator, { for (x, y, cell) in content { self.rustbox.print( x as usize, y as usize, cell.modifier.into(), cell.fg.into(), cell.bg.into(), &cell.symbol, ); } Ok(()) } fn hide_cursor(&mut self) -> Result<(), io::Error> { Ok(()) } fn show_cursor(&mut self) -> Result<(), io::Error> { Ok(()) } fn get_cursor(&mut self) -> io::Result<(u16, u16)> { Err(io::Error::from(io::ErrorKind::Other)) } fn set_cursor(&mut self, x: u16, y: u16) -> io::Result<()> { self.rustbox.set_cursor(x as isize, y as isize); Ok(()) } fn clear(&mut self) -> Result<(), io::Error> { self.rustbox.clear(); Ok(()) } fn size(&self) -> Result { let term_width = self.rustbox.width(); let term_height = self.rustbox.height(); let max = u16::max_value(); Ok(Rect::new( 0, 0, if term_width > usize::from(max) { max } else { term_width as u16 }, if term_height > usize::from(max) { max } else { term_height as u16 }, )) } fn flush(&mut self) -> Result<(), io::Error> { self.rustbox.present(); Ok(()) } } fn rgb_to_byte(r: u8, g: u8, b: u8) -> u16 { u16::from((r & 0xC0) + ((g & 0xE0) >> 2) + ((b & 0xE0) >> 5)) } impl From for rustbox::Color { fn from(color: Color) -> rustbox::Color { match color { Color::Reset => rustbox::Color::Default, Color::Black | Color::Gray | Color::DarkGray => rustbox::Color::Black, Color::Red | Color::LightRed => rustbox::Color::Red, Color::Green | Color::LightGreen => rustbox::Color::Green, Color::Yellow | Color::LightYellow => rustbox::Color::Yellow, Color::Magenta | Color::LightMagenta => rustbox::Color::Magenta, Color::Cyan | Color::LightCyan => rustbox::Color::Cyan, Color::White => rustbox::Color::White, Color::Blue | Color::LightBlue => rustbox::Color::Blue, Color::Indexed(i) => rustbox::Color::Byte(u16::from(i)), Color::Rgb(r, g, b) => rustbox::Color::Byte(rgb_to_byte(r, g, b)), } } } impl From for rustbox::Style { fn from(modifier: Modifier) -> rustbox::Style { let mut result = rustbox::Style::empty(); if modifier.contains(Modifier::BOLD) { result.insert(rustbox::RB_BOLD); } if modifier.contains(Modifier::UNDERLINED) { result.insert(rustbox::RB_UNDERLINE); } if modifier.contains(Modifier::REVERSED) { result.insert(rustbox::RB_REVERSE); } result } }