extern crate pancurses;
use pancurses::{Window, Input, initscr};
pub struct Terminal {
win: Window,
layers: LayerArrangement
}
struct LayerArrangement {
layer_stack: Vec<Layer2D>
}
#[derive(Clone, Debug)]
pub struct Layer {
pub posx: i32,
pub posy: i32,
pub inner_content: String,
content: String,
length: usize
}
#[derive(Clone, Debug)]
pub struct Layer2D {
pub posx: i32,
pub posy: i32,
pub length: usize,
pub height: usize,
pub layers: Vec<Layer>,
char_count: usize,
stack_loc: i32
}
#[derive(Debug, PartialEq)]
pub enum Key {
Alpha(char),
Enter,
Space,
Backspace,
ArrowUp,
ArrowDown,
ArrowLeft,
ArrowRight,
F1,F2,F3,F4,F5,F6,F7,F8,F9,F10,F11,F12
}
impl Layer {
pub fn new(posx: i32, posy: i32) -> Layer {
Layer { posx, posy, content: String::new(), inner_content: String::new(), length: 0 }
}
pub fn get_content(&self) -> String {
self.content.clone()
}
pub fn set_content(&mut self, c: String) -> &mut Layer {
self.content = c;
if self.content.len() > self.length {
self.length = self.content.len();
}
self
}
pub fn inner_to_outer(&mut self) {
self.set_content(self.inner_content.clone());
}
pub fn shrink(&mut self) {
self.length = self.content.len();
}
}
impl Layer2D {
pub fn new(posx: i32, posy: i32, length: usize, height: usize, populator: Layer) -> Layer2D {
let mut l = Layer2D { posx, posy, length, height, layers: vec![], char_count: 0, stack_loc: 0 };
l.populate(populator);
l
}
pub fn populate(&mut self, populator: Layer) {
let n = populator.clone();
self.char_count = n.get_content().len();
self.layers = std::iter::repeat(n).take(self.length * self.height)
.enumerate()
.map(|(i, l)| {
let mut x = l.clone();
x.posx = (i % self.length * self.char_count) as i32;
x.posy = ((i / self.length) as f64).floor() as i32;
x
}).collect();
}
pub fn index(&mut self, x: usize, y: usize) -> &mut Layer {
&mut self.layers[x + y * self.length]
}
pub fn get(&self, x: usize, y: usize) -> &Layer {
&self.layers[x + y * self.length]
}
}
impl LayerArrangement {
fn new() -> LayerArrangement {
LayerArrangement { layer_stack: vec![] }
}
fn push(&mut self, layer: Layer2D) -> &mut Layer2D {
self.layer_stack.push(layer);
self.layer_stack.last_mut().unwrap()
}
fn pop(&mut self) -> Option<Layer2D> {
self.layer_stack.pop()
}
}
fn locate_idx(len: usize, l: i32) -> usize {
match l <= 0 {
false => l as usize,
true => ((len - 1) as i32 + l) as usize
}
}
impl Terminal {
pub fn new() -> Terminal {
let win = initscr();
win.keypad(true);
Terminal { win, layers: LayerArrangement::new() }
}
pub fn add_layer(&mut self, layer: Layer) -> &mut Layer {
let mut r2d = Layer2D::new(layer.posx, layer.posy, 1, 1, layer);
r2d.stack_loc = -(self.layers.layer_stack.len() as i32);
self.layers.push(r2d).index(0, 0)
}
pub fn add_layer2d(&mut self, layer: Layer2D) -> &mut Layer2D {
let mut r = layer.clone();
r.stack_loc = -(self.layers.layer_stack.len() as i32);
self.layers.push(layer)
}
pub fn refresh(&self) {
self.win.refresh();
let here = self.raw_posxy();
for l2d in &self.layers.layer_stack {
self.draw_layer2d(l2d);
}
self.raw_move(here.0, here.1);
self.win.refresh();
}
pub fn layer_front(&mut self) -> &mut Layer2D {
self.layers.layer_stack.last_mut().unwrap()
}
pub fn layer_back(&mut self) -> &mut Layer2D {
self.layers.layer_stack.first_mut().unwrap()
}
pub fn layer_swap(&mut self, a: i32, b: i32) {
let len = self.layers.layer_stack.len();
self.layers.layer_stack.swap(locate_idx(len, a), locate_idx(len, b));
}
pub fn layer_locate(&mut self, l: i32) -> &mut Layer2D {
let len = self.layers.layer_stack.len();
&mut self.layers.layer_stack[locate_idx(len, l)]
}
pub fn draw_layer(&self, layer: &Layer) {
self.raw_move(layer.posx, layer.posy);
self.raw_out_static(" ".repeat(layer.length)); self.raw_out(layer.get_content());
}
pub fn draw_layer_static(&self, layer: &Layer) {
let here = self.raw_posxy();
self.draw_layer(layer);
self.raw_move(here.0, here.1);
}
pub fn draw_layer2d(&self, layer: &Layer2D) {
self.raw_move(layer.posx, layer.posy);
layer.layers.iter().for_each(|l| self.draw_layer_static(l) );
}
pub fn draw_layer2d_static(&self, layer: &Layer) {
let here = self.raw_posxy();
self.draw_layer(layer);
self.raw_move(here.0, here.1);
}
pub fn out(&self, s: String) {
self.win.printw(s);
self.refresh();
}
pub fn out_static(&self, s: String) {
let here = self.raw_posxy();
self.out(s);
self.raw_move(here.0, here.1);
}
pub fn outln(&self, s: String) {
self.win.printw(s);
self.outbr();
}
pub fn outbr(&self) {
self.win.printw(String::from("\n"));
self.refresh();
}
pub fn raw_out(&self, s: String) {
self.win.printw(s);
}
pub fn raw_out_static(&self, s: String) {
let here = self.raw_posxy();
self.raw_out(s);
self.raw_move(here.0, here.1);
}
pub fn raw_outln(&self, s: String) {
self.win.printw(s);
self.raw_br();
}
pub fn raw_br(&self) {
self.win.printw(String::from("\n"));
}
pub fn raw_posxy(&self) -> (i32, i32) {
(self.win.get_cur_x(), self.win.get_cur_y())
}
pub fn raw_posx(&self) -> i32 {
self.win.get_cur_x()
}
pub fn raw_posy(&self) -> i32 {
self.win.get_cur_y()
}
pub fn raw_move(&self, x: i32, y: i32) {
self.win.mv(y, x);
}
pub fn raw_move_offset(&self, xoffs: i32, yoffs: i32) {
self.raw_move(self.raw_posx() + xoffs, self.raw_posy() + yoffs);
}
pub fn raw_move_first(&self) {
self.raw_move(0, self.raw_posy());
}
pub fn raw_move_prev(&self) {
self.raw_move_offset(-1, 0);
}
pub fn raw_move_next(&self) {
self.raw_move_offset(1, 0);
}
pub fn raw_delete(&self) {
self.win.delch();
}
pub fn raw_delete_prev(&self) {
self.raw_move_prev();
self.raw_delete();
}
pub fn raw_delete_offset(&self, xoffs: i32) {
let offs = xoffs / xoffs.abs(); let here = self.raw_posx();
while self.raw_posx() != here + xoffs {
self.raw_move_offset(offs, 0);
self.raw_delete();
}
}
pub fn raw_delete_from(&self, chars: usize) {
self.raw_move_first();
self.raw_move_offset(chars as i32, 0);
self.raw_delete_to(0);
}
pub fn raw_delete_to(&self, x: i32) {
let offs = if x > self.raw_posx() {
1
} else {
-1
};
while self.raw_posx() != x {
self.raw_move_offset(offs, 0);
self.raw_delete();
}
}
pub fn get_char(&self) -> Option<Key> {
match self.win.getch() {
Some(Input::Character('\n')) | Some(Input::Character('\r')) => Some(Key::Enter),
Some(Input::Character('\x08')) => Some(Key::Backspace),
Some(Input::Character(c)) => Some(Key::Alpha(c)),
Some(Input::KeyUp) => Some(Key::ArrowUp),
Some(Input::KeyDown) => Some(Key::ArrowDown),
Some(Input::KeyLeft) => Some(Key::ArrowLeft),
Some(Input::KeyRight) => Some(Key::ArrowRight),
Some(Input::KeyF1) => Some(Key::F1),
Some(Input::KeyF2) => Some(Key::F2),
Some(Input::KeyF3) => Some(Key::F3),
Some(Input::KeyF4) => Some(Key::F4),
Some(Input::KeyF5) => Some(Key::F5),
Some(Input::KeyF6) => Some(Key::F6),
Some(Input::KeyF7) => Some(Key::F7),
Some(Input::KeyF8) => Some(Key::F8),
Some(Input::KeyF9) => Some(Key::F9),
Some(Input::KeyF10) => Some(Key::F10),
Some(Input::KeyF11) => Some(Key::F11),
Some(Input::KeyF12) => Some(Key::F12),
None => None,
_ => None,
}
}
pub fn get_char_hidden(&self) -> Option<Key> {
let here = self.raw_posxy();
let ret = self.get_char();
match ret {
Some(Key::Alpha(c)) => { self.raw_delete_prev(); },
_ | None => ()
}
self.raw_move(here.0, here.1);
ret
}
pub fn ask(&self, prefix: String) -> String {
self.out(prefix);
let mut r = Layer::new(self.raw_posx(), self.raw_posy());
while let Some(i) = self.get_char_hidden() {
match i {
Key::Enter => break,
Key::Backspace => {
if let Some(i) = r.get_content().pop() {
let mut content = r.get_content();
content.pop();
r.set_content(content);
self.draw_layer(&r);
} else {
self.raw_move_next();
continue;
}
},
Key::Alpha(c) => {
let mut content = r.get_content();
content.push(c);
r.set_content(content);
self.draw_layer(&r);
},
_ => continue,
}
}
r.get_content()
}
pub fn mask(&self, prefix: String, mask: char) -> String {
self.out(prefix);
let mut r = Layer::new(self.raw_posx(), self.raw_posy());
let mut s = String::new();
while let Some(i) = self.get_char_hidden() {
match i {
Key::Enter => break,
Key::Backspace => {
if let Some(i) = r.get_content().pop() {
let mut content = r.get_content();
content.pop();
r.set_content(content);
self.draw_layer(&r);
s.pop();
} else {
self.raw_move_next();
continue;
}
},
Key::Alpha(c) => {
let mut content = r.get_content();
content.push(mask);
s.push(c);
r.set_content(content);
self.draw_layer(&r);
},
_ => continue,
}
}
s
}
pub fn yesno(&self, suffix: String, default: bool) -> bool {
let yn: Vec<String> = suffix.split('/').map(|s| String::from(s)).collect();
if yn.len() == 1 {
panic!("Expected a '/' character separating a yes no question!");
}
let mut ynl = Layer::new(self.raw_posx(), self.raw_posy());
let mut y = yn[0].clone();
let mut n = yn[1].clone();
match default {
true => { y = y.to_uppercase(); },
false => { n = n.to_uppercase(); },
}
ynl.set_content(format!("({}/{})", y.clone(), n.clone()));
self.draw_layer(&ynl);
let mut ret = default;
while let Some(i) = self.get_char_hidden() {
match i {
Key::Enter => break,
Key::ArrowRight => { ret = false; },
Key::ArrowLeft => { ret = true; },
_ => continue
}
match ret {
true => { y = { n = n.to_lowercase(); y.to_uppercase() } },
false => { n = { y = y.to_lowercase(); n.to_uppercase() } },
}
ynl.set_content(format!("({}/{})", y.clone(), n.clone()));
self.draw_layer(&ynl);
}
ret
}
pub fn choices(&self, prefix: String, strs: Vec<String>) -> String {
self.outbr();
let mut layers: Vec<Layer> = vec![];
for (i , str) in strs.iter().enumerate() {
let mut l = Layer::new(self.raw_posx(), self.raw_posy() + i as i32);
l.inner_content = str.clone();
if i == 0 {
l.set_content(format!("{}{}", prefix.clone(), l.inner_content.clone()));
} else { l.inner_to_outer(); }
self.draw_layer_static(&l);
layers.push(l);
}
self.raw_move_offset(0, layers.len() as i32);
let mut y = 0;
while let Some(i) = self.get_char_hidden() {
match i {
Key::Enter => break,
Key::ArrowDown => {
if (y < layers.len() - 1) {
y += 1;
}
},
Key::ArrowUp => {
if (y > 0) {
y -= 1;
}
}
_ => continue
}
for (i, l) in layers.iter_mut().enumerate() {
if i == y {
l.set_content(format!("{}{}", prefix.clone(), l.inner_content.clone()));
} else { l.inner_to_outer(); }
self.draw_layer_static(&l);
}
}
layers[y].inner_content.clone()
}
}