various ui stuff
This commit is contained in:
parent
deca53e834
commit
2074b95778
4 changed files with 72 additions and 33 deletions
|
@ -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!(
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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) {}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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<()>;
|
||||||
|
|
Loading…
Reference in a new issue