various ui stuff

This commit is contained in:
Michael Zhang 2021-02-27 00:27:53 -06:00
parent deca53e834
commit 2074b95778
Signed by: michael
GPG key ID: BDA47A31A3C8EE6B
4 changed files with 72 additions and 33 deletions

View file

@ -1,8 +1,8 @@
//! UI //! UI module
mod drawable;
mod table; mod table;
mod tabs; mod tabs;
mod widget;
use std::fmt::Debug; use std::fmt::Debug;
use std::io::{Stdout, Write}; use std::io::{Stdout, Write};
@ -20,9 +20,9 @@ use tokio::time;
use crate::ExitSender; use crate::ExitSender;
use self::drawable::Drawable;
use self::table::Table; use self::table::Table;
use self::tabs::Tabs; use self::tabs::Tabs;
use self::widget::Widget;
const FRAME_DURATION: Duration = Duration::from_millis(20); const FRAME_DURATION: Duration = Duration::from_millis(20);
@ -38,12 +38,13 @@ pub async fn run_ui(mut w: Stdout, exit: ExitSender) -> Result<()> {
execute!(w, cursor::Hide, terminal::EnterAlternateScreen)?; execute!(w, cursor::Hide, terminal::EnterAlternateScreen)?;
terminal::enable_raw_mode()?; terminal::enable_raw_mode()?;
let mut tabs = Tabs::new();
let mut table = Table::default(); let mut table = Table::default();
table.push_row(vec!["ur mom Lol!".to_owned()]); table.push_row(vec!["ur mom Lol!".to_owned()]);
table.push_row(vec!["hek".to_owned()]); table.push_row(vec!["hek".to_owned()]);
let mut tabs = Tabs::new();
tabs.add_tab("Mail", table);
loop { loop {
queue!( queue!(
w, w,
@ -58,16 +59,17 @@ pub async fn run_ui(mut w: Stdout, exit: ExitSender) -> Result<()> {
let (term_width, term_height) = terminal::size()?; let (term_width, term_height) = terminal::size()?;
let bounds = Rect(5, 5, term_width - 10, term_height - 10); let bounds = Rect(5, 5, term_width - 10, term_height - 10);
table.draw(&mut w, bounds)?; // table.draw(&mut w, bounds)?;
tabs.draw(&mut w, bounds)?;
w.flush()?; w.flush()?;
// approx 60fps // approx 60fps
time::sleep(FRAME_DURATION).await; time::sleep(FRAME_DURATION).await;
// check to see if there's even an event this frame. otherwise, just keep going // check to see if there's even an event this frame. otherwise, just keep going
if event::poll(FRAME_DURATION)? { let event = if event::poll(FRAME_DURATION)? {
let event = event::read()?; let event = event::read()?;
table.update(&event); // table.update(&event);
if let Event::Key(KeyEvent { if let Event::Key(KeyEvent {
code: KeyCode::Char('q'), code: KeyCode::Char('q'),
@ -76,7 +78,13 @@ pub async fn run_ui(mut w: Stdout, exit: ExitSender) -> Result<()> {
{ {
break; break;
} }
}
Some(event)
} else {
None
};
tabs.update(event);
} }
execute!( execute!(

View file

@ -7,7 +7,7 @@ use crossterm::{
style::{self, Color}, style::{self, Color},
}; };
use super::{Drawable, Rect, Screen}; use super::{Rect, Screen, Widget};
#[derive(Default)] #[derive(Default)]
pub struct Table { pub struct Table {
@ -16,8 +16,17 @@ pub struct Table {
} }
impl Table { impl Table {
pub fn update(&mut self, event: &Event) { pub fn push_row(&mut self, row: Vec<String>) {
if let Event::Key(KeyEvent { code, .. }) = event { self.rows.push(row);
if self.selected_row.is_none() {
self.selected_row = Some(0);
}
}
}
impl Widget for Table {
fn update(&mut self, event: Option<Event>) {
if let Some(Event::Key(KeyEvent { code, .. })) = event {
match code { match code {
KeyCode::Char('j') => { KeyCode::Char('j') => {
if let Some(selected_row) = &mut self.selected_row { if let Some(selected_row) = &mut self.selected_row {
@ -36,15 +45,6 @@ impl Table {
} }
} }
pub fn push_row(&mut self, row: Vec<String>) {
self.rows.push(row);
if self.selected_row.is_none() {
self.selected_row = Some(0);
}
}
}
impl Drawable for Table {
fn draw(&self, w: &mut Screen, rect: Rect) -> Result<()> { fn draw(&self, w: &mut Screen, rect: Rect) -> Result<()> {
if !self.rows.is_empty() { if !self.rows.is_empty() {
let mut columns = Vec::new(); let mut columns = Vec::new();

View file

@ -2,25 +2,52 @@ use std::collections::HashMap;
use std::io::Write; use std::io::Write;
use anyhow::Result; use anyhow::Result;
use crossterm::{cursor::MoveTo, event::Event};
use super::{Drawable, Rect, Screen}; use super::{Rect, Screen, Widget};
pub struct Tabs { pub struct Tabs {
tabs: HashMap<String, Box<dyn Drawable>>, id: usize,
} active_id: usize,
names: Vec<(usize, String)>,
impl Drawable for Tabs { contents: HashMap<usize, Box<dyn Widget>>,
fn draw(&self, w: &mut Screen, rect: Rect) -> Result<()> {
Ok(())
}
fn invalidate(&mut self) {}
} }
impl Tabs { impl Tabs {
pub fn new() -> Self { pub fn new() -> Self {
Tabs { Tabs {
tabs: HashMap::new(), id: 0,
active_id: 0,
names: Vec::new(),
contents: HashMap::new(),
} }
} }
pub fn add_tab(&mut self, name: impl AsRef<str>, drawable: impl Widget + 'static) {
let id = self.id;
self.id += 1;
self.names.push((id, name.as_ref().to_owned()));
self.contents.insert(id, Box::new(drawable));
}
}
impl Widget for Tabs {
fn update(&mut self, event: Option<Event>) {}
fn draw(&self, w: &mut Screen, rect: Rect) -> Result<()> {
queue!(w, MoveTo(rect.0, rect.1))?;
for (id, name) in self.names.iter() {
println!(" {} ", name);
}
let new_rect = Rect(rect.0, rect.1 + 1, rect.2, rect.3 - 1);
if let Some(widget) = self.contents.get(&self.active_id) {
widget.draw(w, new_rect)?;
}
Ok(())
}
fn invalidate(&mut self) {}
} }

View file

@ -1,10 +1,14 @@
use std::io::Write; use std::io::Write;
use anyhow::Result; use anyhow::Result;
use crossterm::event::Event;
use super::{Rect, Screen}; use super::{Rect, Screen};
pub trait Drawable { pub trait Widget {
/// Updates the widget given an event
fn update(&mut self, event: Option<Event>);
/// Draws this UI element to the screen /// Draws this UI element to the screen
fn draw(&self, w: &mut Screen, rect: Rect) -> Result<()>; fn draw(&self, w: &mut Screen, rect: Rect) -> Result<()>;