#![doc(html_root_url = "https://docs.rs/termris/3.4.5")]
use std::error::Error;
use std::time;
use std::sync::mpsc;
use crossterm::event::Event;
use crossterm::event::{KeyEvent, KeyEventKind, KeyModifiers};
use crossterm::event::KeyCode;
use crossterm::event::{MouseEvent, MouseEventKind, MouseButton};
use prayterm::{Rgb, NopColor};
use mvc_rs::TView;
pub mod packet;
use packet::Packet;
pub mod model;
use model::Model;
pub mod view;
use view::{NColor, View};
pub mod controller;
use controller::Controller;
pub mod stat;
pub struct Termris {
pub v: View<NColor>,
pub c: Controller,
pub t: time::Instant,
pub d: time::Duration,
pub ms: time::Duration
}
impl Drop for Termris {
fn drop(&mut self) {
self.v.tm.fin().expect("fin");
}
}
impl Termris {
pub fn new() -> Result<Self, Box<dyn Error>> {
let m = Model::new(10, 20);
let colors = [ NColor::Black, NColor::Black_,
NColor::Gray, NColor::Gray_,
NColor::Red, NColor::Red_,
NColor::Green, NColor::Green_,
NColor::Blue, NColor::Blue_,
NColor::Cyan, NColor::Cyan_,
NColor::Magenta, NColor::Magenta_,
NColor::Yellow, NColor::Yellow_,
NColor::Orange, NColor::Orange_,
NColor::Violet, NColor::Violet_,
NColor::White, NColor::White_,
NColor::LightRed, NColor::LightRed_,
NColor::LightGreen, NColor::LightGreen_,
NColor::LightBlue, NColor::LightBlue_,
NColor::LightBlack, NColor::LightBlack_,
NColor::DarkGray, NColor::DarkGray_].to_vec();
let v = View::new(colors)?;
let ms = 120; let c = Controller::new(m, ms);
let mut s = Termris{v, c,
t: time::Instant::now(), d: time::Duration::new(0, ms * 1_000_000), ms: time::Duration::from_millis(1)};
s.v.tm.begin()?;
s.c.init(&mut s.v)?;
Ok(s)
}
pub fn status(&mut self, h: u16, st: u16, c: u16, msg: &String) ->
Result<(), Box<dyn Error>> {
self.v.wr(Packet{x: 0, y: self.v.tm.h - h, st, bgc: c, fgc: c + 1, msg})?;
Ok(())
}
pub fn stat(&mut self, h: u16, st: u16,
bgc: impl NopColor, fgc: impl NopColor, msg: &String) ->
Result<(), Box<dyn Error>> {
self.v.tm.wr(0, self.v.tm.h - h, st, bgc, fgc, msg)?;
Ok(())
}
pub fn proc(&mut self, rx: &mpsc::Receiver<Result<Event, std::io::Error>>) ->
Result<bool, Box<dyn Error>> {
spin_sleep::sleep(self.ms);
match rx.recv_timeout(time::Duration::new(0, 0)) {
Err(mpsc::RecvTimeoutError::Disconnected) => Err("Disconnected".into()),
Err(mpsc::RecvTimeoutError::Timeout) => { self.status(3, 3, 20, &format!("{:?}", self.t.elapsed()))?;
self.c.refresh(&mut self.v)?;
let u = time::Instant::now();
if let Some(n) = u.checked_duration_since(self.t) {
if n >= self.d / self.c.speed() {
if !self.c.proc_idle() { return Ok(false); }
self.t = u;
}
} else {
()
}
Ok(true)
},
Ok(ev) => {
Ok(match ev {
Ok(Event::Key(k)) => {
let f = match k {
KeyEvent{kind: KeyEventKind::Press, state: _, code, modifiers} => {
match (code, modifiers) {
(KeyCode::Char('x'), KeyModifiers::ALT) => false,
(KeyCode::Char('c'), KeyModifiers::CONTROL) => false,
(KeyCode::Char('q'), _) => false,
(KeyCode::Char('\x1b'), _) => false,
(KeyCode::Esc, _) => false,
_ => true }
},
_ => true };
if !f { return Ok(false); }
if self.c.key(k) { self.t -= self.d; }
true
},
Ok(Event::Mouse(MouseEvent{kind, column: x, row: y, modifiers: _})) => {
match kind {
MouseEventKind::Moved => {
self.status(4, 3, 18, &format!("mouse[{}, {}]", x, y))?;
true
},
MouseEventKind::Down(MouseButton::Left) => {
self.status(5, 3, 16, &format!("click[{}, {}]", x, y))?;
true
},
_ => true
}
},
Ok(Event::Resize(w, h)) => {
self.status(6, 3, 2, &format!("resize[{}, {}]", w, h))?;
true
},
_ => true
})
}
}
}
pub fn mainloop(&mut self) -> Result<(), Box<dyn Error>> {
let (_tx, rx) = self.v.tm.prepare_thread(self.ms)?;
loop { if !self.proc(&rx)? { break; } }
self.c.fin(&mut self.v)?;
Ok(())
}
}
pub fn main() -> Result<(), Box<dyn Error>> {
let mut tr = Termris::new()?;
tr.stat(50, 3, NColor::Red, NColor::Cyan, &"thread start".to_string())?;
tr.stat(49, 3, NColor::Green, NColor::Magenta, &"main loop".to_string())?;
tr.mainloop()?;
tr.stat(2, 3, Rgb(0, 0, 255), Rgb(255, 255, 0), &"end".to_string())?;
Ok(())
}
#[cfg(test)]
mod tests {
#[test]
fn test_a() {
assert_eq!(true, true);
}
}