ghassmo 4 лет назад
Родитель
Сommit
31993efb71
7 измененных файлов с 373 добавлено и 0 удалено
  1. 30 0
      Cargo.lock
  2. 9 0
      Cargo.toml
  3. 33 0
      src/bin/tui_ex.rs
  4. 1 0
      src/lib.rs
  5. 117 0
      src/tui/app.rs
  6. 6 0
      src/tui/mod.rs
  7. 177 0
      src/tui/widget.rs

+ 30 - 0
Cargo.lock

@@ -1335,6 +1335,7 @@ dependencies = [
  "bytes",
  "chrono",
  "clap",
+ "crossbeam-channel 0.5.1",
  "crypto_api_chachapoly",
  "dirs 4.0.0",
  "easy-parallel",
@@ -1348,6 +1349,7 @@ dependencies = [
  "incrementalmerkletree",
  "keccak-hasher",
  "lazy_static",
+ "libc",
  "libsqlite3-sys",
  "log",
  "native-tls",
@@ -1373,6 +1375,7 @@ dependencies = [
  "spl-token",
  "sqlx",
  "subtle",
+ "termion",
  "thiserror",
  "toml",
  "tungstenite",
@@ -3008,6 +3011,12 @@ version = "0.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3"
 
+[[package]]
+name = "numtoa"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef"
+
 [[package]]
 name = "object"
 version = "0.27.1"
@@ -3705,6 +3714,15 @@ dependencies = [
  "bitflags",
 ]
 
+[[package]]
+name = "redox_termios"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8440d8acb4fd3d277125b4bd01a6f38aee8d814b3b5fc09b3f2b825d37d3fe8f"
+dependencies = [
+ "redox_syscall 0.2.10",
+]
+
 [[package]]
 name = "redox_users"
 version = "0.3.5"
@@ -5173,6 +5191,18 @@ dependencies = [
  "winapi 0.3.9",
 ]
 
+[[package]]
+name = "termion"
+version = "1.5.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "077185e2eac69c3f8379a4298e1e07cd36beb962290d4a51199acf0fdc10607e"
+dependencies = [
+ "libc",
+ "numtoa",
+ "redox_syscall 0.2.10",
+ "redox_termios",
+]
+
 [[package]]
 name = "textwrap"
 version = "0.11.0"

+ 9 - 0
Cargo.toml

@@ -99,15 +99,20 @@ solana-sdk = {version = "1.8.11", optional = true}
 spl-associated-token-account = {version = "1.0.3", features = ["no-entrypoint"], optional = true}
 spl-token = {version = "3.2.0", features = ["no-entrypoint"], optional = true}
 
+# Darkpulse and tui dependencies
 aes-gcm = {version = "0.9.4", optional = true}
 chrono = {version = "0.4.19", optional = true}
 rusqlite = {version = "0.26.3", optional = true}
+crossbeam-channel = { version = "0.5.1", optional = true}
+libc = { version = "0.2.112", optional = true}
+termion = { version = "1.5.6", optional = true}
 
 [features]
 btc = ["bdk", "bitcoin", "secp256k1"]
 eth = ["keccak-hasher", "hash-db"]
 sol = ["solana-sdk", "solana-client", "spl-token", "spl-associated-token-account"]
 darkpulse = ["aes-gcm", "chrono","rusqlite"]
+tui = ["termion", "chrono","libc", "crossbeam-channel"]
 
 [[bin]]         
 name = "darkpulse"    
@@ -117,6 +122,10 @@ required-features = ["darkpulse"]
 name = "eth"    
 required-features = ["eth"]
 
+[[bin]]         
+name = "tui_ex"    
+required-features = ["tui"]
+
 [[example]]
 name = "net"
 path = "example/net.rs"

+ 33 - 0
src/bin/tui_ex.rs

@@ -0,0 +1,33 @@
+
+use drk::tui::{App, HBox, VBox, Widget};
+use drk::Result;
+
+async fn start() -> Result<()> {
+    let wv1 = vec![Widget::new("V1".into())?];
+
+    let wh1 = vec![Widget::new("H1".into())?];
+
+    let wv2 = vec![Widget::new("V2".into())?];
+
+    let wv3 = vec![Widget::new("V3".into())?, Widget::new("V4".into())?];
+
+    let v_box1 = Box::new(VBox::new(wv1.clone(), 2));
+    let h_box1 = Box::new(HBox::new(wh1.clone(), 2));
+    let v_box2 = Box::new(VBox::new(wv2.clone(), 2));
+    let v_box3 = Box::new(VBox::new(wv3.clone(), 1));
+
+    let mut app = App::new()?;
+
+    app.add_layout(v_box1)?;
+    app.add_layout(h_box1)?;
+    app.add_layout(v_box2)?;
+    app.add_layout(v_box3)?;
+
+    app.run().await?;
+
+    Ok(())
+}
+
+fn main() -> Result<()> {
+    smol::future::block_on(start())
+}

+ 1 - 0
src/lib.rs

@@ -18,6 +18,7 @@ pub mod util;
 pub mod vm;
 pub mod vm_serial;
 pub mod wallet;
+pub mod tui;
 
 #[cfg(feature = "darkpulse")]
 pub mod darkpulse;

+ 117 - 0
src/tui/app.rs

@@ -0,0 +1,117 @@
+use async_std::sync::Mutex;
+use std::io::{Stdin, Stdout, Write};
+
+use termion::{
+    clear, cursor,
+    event::Key,
+    input::{Keys, TermRead},
+    raw::{IntoRawMode, RawTerminal},
+};
+
+use crate::Result;
+use super::Layout;
+
+pub struct App {
+    layouts: Vec<Box<dyn Layout>>,
+    stdin: Mutex<Keys<Stdin>>,
+    stdout: RawTerminal<Stdout>,
+}
+
+impl App {
+    pub fn new() -> Result<Self> {
+        let stdin = Mutex::new(std::io::stdin().keys());
+
+        let stdout = std::io::stdout();
+        let stdout = stdout.into_raw_mode()?;
+
+        Ok(Self {
+            stdin,
+            stdout,
+            layouts: vec![],
+        })
+    }
+
+    fn clear(&mut self) -> Result<()> {
+        self.hide_cursor()?;
+        write!(self.stdout, "{}", clear::All)?;
+        Ok(())
+    }
+
+    fn hide_cursor(&mut self) -> Result<()> {
+        write!(self.stdout, "{}", cursor::Hide)?;
+        Ok(())
+    }
+
+    fn show_cursor(&mut self) -> Result<()> {
+        write!(self.stdout, "{}", cursor::Show)?;
+        Ok(())
+    }
+
+    fn _move_the_cursor(&mut self, x: usize, y: usize) -> Result<()> {
+        write!(self.stdout, "{}", cursor::Goto(1 + x as u16, 1 + y as u16))?;
+        Ok(())
+    }
+
+    fn flush(&mut self) -> Result<()> {
+        self.stdout.flush()?;
+        Ok(())
+    }
+
+    async fn _get_stdin_key(&self) -> Option<Key> {
+        match self.stdin.lock().await.next() {
+            Some(Ok(key)) => Some(key),
+            _ => None,
+        }
+    }
+
+    pub fn add_layout(&mut self, layout: Box<dyn Layout>) -> Result<()> {
+        self.layouts.push(layout);
+        Ok(())
+    }
+
+    pub async fn run(&mut self) -> Result<()> {
+        self.clear()?;
+
+        let mut terminal_width = termion::terminal_size()?.0 as usize;
+        let mut terminal_height = termion::terminal_size()?.1 as usize;
+
+        let mut last_box_x = 0;
+        let mut last_box_y = 0;
+
+        for layout in self.layouts.iter_mut() {
+            let (box_x, box_y) = layout.draw(
+                &mut self.stdout,
+                last_box_x,
+                last_box_y,
+                terminal_width as usize,
+                terminal_height as usize,
+            )?;
+
+            if last_box_x != box_x {
+                last_box_x += box_x;
+                if terminal_width > box_x {
+                    terminal_width -= box_x;
+                } else {
+                    break;
+                }
+            }
+
+            if last_box_y != box_y {
+                last_box_y += box_y;
+                if terminal_height > box_y {
+                    terminal_height -= box_y;
+                } else {
+                    break;
+                }
+            }
+        }
+
+        self.flush()?;
+
+        async_std::task::sleep(std::time::Duration::from_secs(5)).await;
+
+        self.show_cursor()?;
+
+        Ok(())
+    }
+}

+ 6 - 0
src/tui/mod.rs

@@ -0,0 +1,6 @@
+pub mod widget;
+pub mod app;
+
+pub use widget::{HBox, VBox, Widget, Layout};
+pub use app::App;
+

+ 177 - 0
src/tui/widget.rs

@@ -0,0 +1,177 @@
+use std::io::{Stdout, Write};
+
+use termion::{cursor, raw::RawTerminal};
+
+use crate::Result;
+
+#[derive(Clone)]
+pub struct Widget {
+    pub width: usize,
+    pub height: usize,
+    pub x: usize,
+    pub y: usize,
+    title: String,
+}
+
+impl Widget {
+    pub fn new(title: String) -> Result<Widget> {
+        Ok(Widget {
+            width: 0,
+            height: 0,
+            x: 0,
+            y: 0,
+            title,
+        })
+    }
+
+    pub fn print(
+        &self,
+        stdout: &mut RawTerminal<Stdout>,
+        x: usize,
+        y: usize,
+        text: &str,
+    ) -> Result<()> {
+        write!(
+            stdout,
+            "{}{}",
+            cursor::Goto(1 + x as u16, 1 + y as u16),
+            text
+        )?;
+        Ok(())
+    }
+
+    pub fn print_border(&self, stdout: &mut RawTerminal<Stdout>) -> Result<()> {
+        let x = self.x;
+        let y = self.y;
+        let width = self.width;
+        let height = self.height;
+
+        let hline = "─";
+        let vline = "│";
+        let topleftcorner = "┌";
+        let toprightcorner = "┐";
+        let downleftcorner = "└";
+        let downrightcorner = "┘";
+
+        self.print(stdout, x, y, topleftcorner)?;
+        self.print(stdout, x, y + height, downleftcorner)?;
+
+        self.print(stdout, x + width - 1, y, toprightcorner)?;
+        self.print(stdout, x + width - 1, y + height, downrightcorner)?;
+
+        for j in (y + 1)..(y + height) {
+            self.print(stdout, x, j, vline)?;
+            self.print(stdout, x + width - 1, j, vline)?;
+        }
+
+        for i in (x + 1)..(x + width - 1) {
+            self.print(stdout, i, y, hline)?;
+            self.print(stdout, i, y + height, hline)?;
+        }
+
+        Ok(())
+    }
+
+    pub fn clear_current_line(&self, stdout: &mut RawTerminal<Stdout>) -> Result<()> {
+        let width = self.width;
+        for i in self.x..(width - 3) {
+            self.print(stdout, i, self.y, " ")?;
+        }
+        Ok(())
+    }
+
+    pub fn draw(&self, stdout: &mut RawTerminal<Stdout>) -> Result<()> {
+        self.print_border(stdout)?;
+        self.print(
+            stdout,
+            self.x + 3,
+            self.y,
+            &format!(" {} ", &self.title.clone()),
+        )?;
+        Ok(())
+    }
+}
+
+pub trait Layout {
+    fn draw(
+        &mut self,
+        stdout: &mut RawTerminal<Stdout>,
+        x: usize,
+        y: usize,
+        layout_width: usize,
+        layout_height: usize,
+    ) -> Result<(usize, usize)>;
+}
+
+pub struct VBox {
+    widgets: Vec<Widget>,
+    width: usize,
+}
+
+impl VBox {
+    pub fn new(widgets: Vec<Widget>, width: usize) -> Self {
+        Self { widgets, width }
+    }
+}
+
+impl Layout for VBox {
+    fn draw(
+        &mut self,
+        stdout: &mut RawTerminal<Stdout>,
+        x: usize,
+        y: usize,
+        layout_width: usize,
+        layout_height: usize,
+    ) -> Result<(usize, usize)> {
+        let len = self.widgets.len();
+
+        let widget_width = layout_width / self.width;
+
+        for (i, widget) in self.widgets.iter_mut().enumerate() {
+            widget.width = widget_width - 1;
+            widget.height = (layout_height / len) - 1;
+            widget.x = x;
+            widget.y = (widget.height + 1) * i + y;
+            widget.draw(stdout)?;
+        }
+
+        Ok((widget_width, y))
+    }
+}
+
+pub struct HBox {
+    widgets: Vec<Widget>,
+    pub height: usize,
+}
+
+impl HBox {
+    pub fn new(widgets: Vec<Widget>, height: usize) -> Self {
+        Self { widgets, height }
+    }
+}
+
+impl Layout for HBox {
+    fn draw(
+        &mut self,
+        stdout: &mut RawTerminal<Stdout>,
+        x: usize,
+        y: usize,
+        layout_width: usize,
+        layout_height: usize,
+    ) -> Result<(usize, usize)> {
+
+        let len = self.widgets.len();
+
+        let widget_height = layout_height / self.height;
+
+        for (i, widget) in self.widgets.iter_mut().enumerate() {
+            widget.width = layout_width  / len - 1;
+            widget.height = widget_height - 1;
+            widget.x = (widget.width + 1) * i + x;
+            widget.y = y;
+            widget.draw(stdout)?;
+        }
+
+        Ok((x, widget_height))
+    }
+}