diff --git a/src/ui/mod.rs b/src/ui/mod.rs index 616c056..2d9b921 100644 --- a/src/ui/mod.rs +++ b/src/ui/mod.rs @@ -1,8 +1,8 @@ -//! UI +//! UI module -mod drawable; mod table; mod tabs; +mod widget; use std::fmt::Debug; use std::io::{Stdout, Write}; @@ -20,9 +20,9 @@ use tokio::time; use crate::ExitSender; -use self::drawable::Drawable; use self::table::Table; use self::tabs::Tabs; +use self::widget::Widget; 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)?; terminal::enable_raw_mode()?; - let mut tabs = Tabs::new(); - let mut table = Table::default(); table.push_row(vec!["ur mom Lol!".to_owned()]); table.push_row(vec!["hek".to_owned()]); + let mut tabs = Tabs::new(); + tabs.add_tab("Mail", table); + loop { queue!( w, @@ -58,16 +59,17 @@ pub async fn run_ui(mut w: Stdout, exit: ExitSender) -> Result<()> { let (term_width, term_height) = terminal::size()?; 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()?; // approx 60fps time::sleep(FRAME_DURATION).await; // 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()?; - table.update(&event); + // table.update(&event); if let Event::Key(KeyEvent { code: KeyCode::Char('q'), @@ -76,7 +78,13 @@ pub async fn run_ui(mut w: Stdout, exit: ExitSender) -> Result<()> { { break; } - } + + Some(event) + } else { + None + }; + + tabs.update(event); } execute!( diff --git a/src/ui/table.rs b/src/ui/table.rs index 8d769c0..377bb8d 100644 --- a/src/ui/table.rs +++ b/src/ui/table.rs @@ -7,7 +7,7 @@ use crossterm::{ style::{self, Color}, }; -use super::{Drawable, Rect, Screen}; +use super::{Rect, Screen, Widget}; #[derive(Default)] pub struct Table { @@ -16,8 +16,17 @@ pub struct Table { } impl Table { - pub fn update(&mut self, event: &Event) { - if let Event::Key(KeyEvent { code, .. }) = event { + pub fn push_row(&mut self, row: Vec) { + 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) { + if let Some(Event::Key(KeyEvent { code, .. })) = event { match code { KeyCode::Char('j') => { if let Some(selected_row) = &mut self.selected_row { @@ -36,15 +45,6 @@ impl Table { } } - pub fn push_row(&mut self, row: Vec) { - 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<()> { if !self.rows.is_empty() { let mut columns = Vec::new(); diff --git a/src/ui/tabs.rs b/src/ui/tabs.rs index 4decd9b..2a2474f 100644 --- a/src/ui/tabs.rs +++ b/src/ui/tabs.rs @@ -2,25 +2,52 @@ use std::collections::HashMap; use std::io::Write; use anyhow::Result; +use crossterm::{cursor::MoveTo, event::Event}; -use super::{Drawable, Rect, Screen}; +use super::{Rect, Screen, Widget}; pub struct Tabs { - tabs: HashMap>, -} - -impl Drawable for Tabs { - fn draw(&self, w: &mut Screen, rect: Rect) -> Result<()> { - Ok(()) - } - - fn invalidate(&mut self) {} + id: usize, + active_id: usize, + names: Vec<(usize, String)>, + contents: HashMap>, } impl Tabs { pub fn new() -> Self { Tabs { - tabs: HashMap::new(), + id: 0, + active_id: 0, + names: Vec::new(), + contents: HashMap::new(), } } + + pub fn add_tab(&mut self, name: impl AsRef, 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) {} + + 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) {} } diff --git a/src/ui/drawable.rs b/src/ui/widget.rs similarity index 65% rename from src/ui/drawable.rs rename to src/ui/widget.rs index 14cad8a..7e53c28 100644 --- a/src/ui/drawable.rs +++ b/src/ui/widget.rs @@ -1,10 +1,14 @@ use std::io::Write; use anyhow::Result; +use crossterm::event::Event; use super::{Rect, Screen}; -pub trait Drawable { +pub trait Widget { + /// Updates the widget given an event + fn update(&mut self, event: Option); + /// Draws this UI element to the screen fn draw(&self, w: &mut Screen, rect: Rect) -> Result<()>;