use backend;
use event;
use theme;
use utf8;
use ncurses;
pub struct NcursesBackend;
impl backend::Backend for NcursesBackend {
fn init() {
::std::env::set_var("ESCDELAY", "25");
ncurses::setlocale(ncurses::LcCategory::all, "");
ncurses::initscr();
ncurses::keypad(ncurses::stdscr, true);
ncurses::noecho();
ncurses::cbreak();
ncurses::start_color();
ncurses::curs_set(ncurses::CURSOR_VISIBILITY::CURSOR_INVISIBLE);
ncurses::wbkgd(ncurses::stdscr,
ncurses::COLOR_PAIR(theme::ColorStyle::Background.id()));
}
fn screen_size() -> (usize, usize) {
let mut x: i32 = 0;
let mut y: i32 = 0;
ncurses::getmaxyx(ncurses::stdscr, &mut y, &mut x);
(x as usize, y as usize)
}
fn has_colors() -> bool {
ncurses::has_colors()
}
fn finish() {
ncurses::endwin();
}
fn init_color_style(style: theme::ColorStyle, foreground: &theme::Color,
background: &theme::Color) {
ncurses::init_pair(style.id(),
find_closest(foreground) as i16,
find_closest(background) as i16);
}
fn with_color<F: FnOnce()>(color: theme::ColorStyle, f: F) {
let mut current_style: ncurses::attr_t = 0;
let mut current_color: i16 = 0;
ncurses::attr_get(&mut current_style, &mut current_color);
let style = ncurses::COLOR_PAIR(color.id());
ncurses::attron(style);
f();
ncurses::attron(current_style);
}
fn with_effect<F: FnOnce()>(effect: theme::Effect, f: F) {
let style = match effect {
theme::Effect::Reverse => ncurses::A_REVERSE(),
theme::Effect::Simple => ncurses::A_NORMAL(),
};
ncurses::attron(style);
f();
ncurses::attroff(style);
}
fn clear() {
ncurses::clear();
}
fn refresh() {
ncurses::refresh();
}
fn print_at((x, y): (usize, usize), text: &str) {
ncurses::mvaddstr(y as i32, x as i32, text);
}
fn poll_event() -> event::Event {
let ch: i32 = ncurses::getch();
if 32 <= ch && ch < 0x100 && ch != 127 {
event::Event::Char(utf8::read_char(ch as u8,
|| ncurses::getch() as u8)
.unwrap())
} else {
event::Event::Key(parse_ncurses_char(ch))
}
}
fn set_refresh_rate(fps: u32) {
if fps == 0 {
ncurses::timeout(-1);
} else {
ncurses::timeout(1000 / fps as i32);
}
}
}
fn parse_ncurses_char(ch: i32) -> event::Key {
match ch {
9 => event::Key::Tab,
10 |
ncurses::KEY_ENTER => event::Key::Enter,
27 => event::Key::Esc,
127 |
ncurses::KEY_BACKSPACE => event::Key::Backspace,
410 => event::Key::Resize,
519 => event::Key::AltDel,
520 => event::Key::AltShiftDel,
521 => event::Key::CtrlDel,
522 => event::Key::CtrlShiftDel,
525 => event::Key::AltDown,
526 => event::Key::AltShiftDown,
527 => event::Key::CtrlDown,
528 => event::Key::CtrlShiftDown,
529 => event::Key::CtrlAltDown,
530 => event::Key::AltEnd,
531 => event::Key::AltShiftEnd,
532 => event::Key::CtrlEnd,
533 => event::Key::CtrlShiftEnd,
534 => event::Key::CtrlAltEnd,
535 => event::Key::AltHome,
536 => event::Key::AltShiftHome,
537 => event::Key::CtrlHome,
538 => event::Key::CtrlShiftHome,
539 => event::Key::CtrlAltHome,
540 => event::Key::AltIns,
542 => event::Key::CtrlIns,
544 => event::Key::CtrlAltIns,
545 => event::Key::AltLeft,
546 => event::Key::AltShiftLeft,
547 => event::Key::CtrlLeft,
548 => event::Key::CtrlShiftLeft,
549 => event::Key::CtrlAltLeft,
550 => event::Key::AltPageDown,
551 => event::Key::AltShiftPageDown,
552 => event::Key::CtrlPageDown,
553 => event::Key::CtrlShiftPageDown,
554 => event::Key::CtrlAltPageDown,
555 => event::Key::AltPageUp,
556 => event::Key::AltShiftPageUp,
557 => event::Key::CtrlPageUp,
558 => event::Key::CtrlShiftPageUp,
559 => event::Key::CtrlAltPageUp,
560 => event::Key::AltRight,
561 => event::Key::AltShiftRight,
562 => event::Key::CtrlRight,
563 => event::Key::CtrlShiftRight,
564 => event::Key::CtrlAltRight,
566 => event::Key::AltUp,
567 => event::Key::AltShiftUp,
568 => event::Key::CtrlUp,
569 => event::Key::CtrlShiftUp,
570 => event::Key::CtrlAltUp,
ncurses::KEY_B2 => event::Key::NumpadCenter,
ncurses::KEY_DC => event::Key::Del,
ncurses::KEY_IC => event::Key::Ins,
ncurses::KEY_BTAB => event::Key::ShiftTab,
ncurses::KEY_SLEFT => event::Key::ShiftLeft,
ncurses::KEY_SRIGHT => event::Key::ShiftRight,
ncurses::KEY_LEFT => event::Key::Left,
ncurses::KEY_RIGHT => event::Key::Right,
ncurses::KEY_UP => event::Key::Up,
ncurses::KEY_DOWN => event::Key::Down,
ncurses::KEY_SR => event::Key::ShiftUp,
ncurses::KEY_SF => event::Key::ShiftDown,
ncurses::KEY_PPAGE => event::Key::PageUp,
ncurses::KEY_NPAGE => event::Key::PageDown,
ncurses::KEY_HOME => event::Key::Home,
ncurses::KEY_END => event::Key::End,
ncurses::KEY_SHOME => event::Key::ShiftHome,
ncurses::KEY_SEND => event::Key::ShiftEnd,
ncurses::KEY_SDC => event::Key::ShiftDel,
ncurses::KEY_SNEXT => event::Key::ShiftPageDown,
ncurses::KEY_SPREVIOUS => event::Key::ShiftPageUp,
f @ ncurses::KEY_F1...ncurses::KEY_F12 => {
event::Key::F((f - ncurses::KEY_F0) as u8)
}
f @ 277...288 => event::Key::ShiftF((f - 277) as u8),
f @ 289...300 => event::Key::CtrlF((f - 289) as u8),
f @ 301...312 => event::Key::CtrlShiftF((f - 300) as u8),
f @ 313...324 => event::Key::AltF((f - 313) as u8),
c @ 1...7 | c @ 11...25 => {
event::Key::CtrlChar((b'a' + (c - 1) as u8) as char)
}
_ => event::Key::Unknown(ch),
}
}
fn find_closest(color: &theme::Color) -> u8 {
match *color {
theme::Color::Black => 0,
theme::Color::Red => 1,
theme::Color::Green => 2,
theme::Color::Yellow => 3,
theme::Color::Blue => 4,
theme::Color::Magenta => 5,
theme::Color::Cyan => 6,
theme::Color::White => 7,
theme::Color::Rgb(r, g, b) => {
let r = 6 * r as u16 / 256;
let g = 6 * g as u16 / 256;
let b = 6 * b as u16 / 256;
(16 + 36 * r + 6 * g + b) as u8
}
theme::Color::RgbLowRes(r, g, b) => (16 + 36 * r + 6 * g + b) as u8,
}
}