use grid::Grid;
use pancurses::COLOR_PAIR;
use pancurses::{endwin, start_color, Window};
use std::fmt::Display;
use thiserror::Error;
pub use pancurses::Input;
#[derive(Debug, Default)]
pub struct FryingPan {
colors: bool,
hide_cursor: bool,
no_delay: bool,
}
impl FryingPan {
pub fn color(&mut self, enabled: bool) -> &mut FryingPan {
self.colors = enabled;
self
}
pub fn hide_cursor(&mut self, enabled: bool) -> &mut FryingPan {
self.hide_cursor = enabled;
self
}
pub fn no_delay(&mut self, enabled: bool) -> &mut FryingPan {
self.no_delay = enabled;
self
}
pub fn build(&mut self) -> Result<Pancake, Error> {
let win = pancurses::initscr();
if self.colors && pancurses::has_colors() {
start_color();
} else if self.colors {
return Err(Error::TermNoColor);
}
if self.hide_cursor {
pancurses::curs_set(0);
}
if self.no_delay {
win.nodelay(self.no_delay);
}
win.keypad(true);
Ok(Pancake {
win,
})
}
}
pub struct Pancake {
win: Window,
}
impl Pancake {
pub fn render_panel(&self, panel: &Panel) {
for y in 0..panel.grid.rows() {
for (x, ch) in panel.grid.iter_row(y).enumerate() {
for a in panel.attr.get(y, x).unwrap() {
self.win.attron(*a);
}
self.win.mvaddstr(
(panel.position.y + y) as i32,
(panel.position.x + x) as i32,
ch.to_string(),
);
for a in panel.attr.get(y, x).unwrap() {
self.win.attroff(*a);
}
}
}
}
pub fn get_char(&self) -> Option<Input> {
self.win.getch()
}
pub fn erase(&self) {
self.win.erase();
}
pub fn refresh(&self) {
self.win.refresh();
}
pub fn quit(&self) {
endwin();
}
}
pub struct Panel {
pub position: Point,
pub cursor: Point,
grid: Grid<char>,
attr: Grid<Vec<chtype>>,
}
impl Panel {
pub fn new(position: Point, rows: usize, cols: usize) -> Self {
let mut grid = Grid::new(rows, cols);
grid.fill(' ');
let mut attr = Grid::new(rows, cols);
attr.fill(Vec::new());
Panel {
position,
grid,
attr,
cursor: Point::new(),
}
}
pub fn print<T>(&mut self, string: T)
where
T: Display,
{
let string = string.to_string();
for (i, ch) in string.chars().enumerate() {
if let Some(c) = self.grid.get_mut(self.cursor.y, self.cursor.x + i) {
*c = ch;
}
}
}
pub fn mv_print<T>(&mut self, position: Point, string: T)
where
T: Display,
{
self.cursor = position;
self.print(string);
}
pub fn attr_on(&mut self, attr: chtype) -> Result<(), Error> {
if let Some(vec) = self.attr.get_mut(self.cursor.y, self.cursor.x) {
vec.push(attr);
Ok(())
} else {
Err(Error::OutOfBoundsIndex)
}
}
pub fn attr_off(&mut self, attr: chtype) -> Result<(), Error> {
if let Some(vec) = self.attr.get_mut(self.cursor.y, self.cursor.x) {
let mut indices = Vec::new();
for (i, a) in vec.iter().enumerate() {
if *a == attr {
indices.push(i);
}
}
for index in indices {
vec.remove(index);
}
Ok(())
} else {
Err(Error::OutOfBoundsIndex)
}
}
pub fn erase(&mut self) {
self.grid.fill(' ');
self.attr.fill(Vec::new());
}
pub fn draw_box(&mut self) {
let cols = self.grid.cols() - 1;
let rows = self.grid.rows() - 1;
for ch in self.grid.iter_row_mut(0) {
*ch = '─'
}
for ch in self.grid.iter_row_mut(rows) {
*ch = '─'
}
for ch in self.grid.iter_col_mut(0) {
*ch = '│'
}
for ch in self.grid.iter_col_mut(cols) {
*ch = '│'
}
*self.grid.get_mut(0, 0).unwrap() = '┌';
*self.grid.get_mut(rows, 0).unwrap() = '└';
*self.grid.get_mut(0, cols).unwrap() = '┐';
*self.grid.get_mut(rows, cols).unwrap() = '┘';
}
}
pub struct Point {
pub x: usize,
pub y: usize,
}
impl Point {
pub fn new() -> Self {
Point { y: 0, x: 0 }
}
pub fn from(x: usize, y: usize) -> Self {
Point { x, y }
}
}
impl Default for Point {
fn default() -> Self {
Point::new()
}
}
#[non_exhaustive]
#[derive(Error, Debug)]
pub enum Error {
#[error("Terminal does not support color")]
TermNoColor,
#[error("Cursor index out of bounds")]
OutOfBoundsIndex,
}
pub use pancurses::A_BLINK;
pub use pancurses::A_BOLD;
pub use pancurses::A_DIM;
pub use pancurses::A_ITALIC;
pub use pancurses::A_UNDERLINE;
pub use pancurses::COLOR_BLACK;
pub use pancurses::COLOR_BLUE;
pub use pancurses::COLOR_CYAN;
pub use pancurses::COLOR_GREEN;
pub use pancurses::COLOR_MAGENTA;
pub use pancurses::COLOR_RED;
pub use pancurses::COLOR_WHITE;
pub use pancurses::COLOR_YELLOW;
pub use pancurses::init_pair;
pub fn color_pair(color_pair: i16) -> u32 {
COLOR_PAIR(color_pair as u32)
}
pub use pancurses::chtype;