add drawbuf
This commit is contained in:
parent
30b481ee64
commit
631fdd8b73
5 changed files with 103 additions and 42 deletions
53
src/ui/drawbuf.rs
Normal file
53
src/ui/drawbuf.rs
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
use std::ops::Range;
|
||||||
|
|
||||||
|
use anyhow::Result;
|
||||||
|
use crossterm::{
|
||||||
|
cursor::MoveTo,
|
||||||
|
style::{Color, SetBackgroundColor, SetForegroundColor},
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::{Rect, Screen};
|
||||||
|
|
||||||
|
pub struct DrawBuf {
|
||||||
|
rect: Rect,
|
||||||
|
buffer: Vec<Cell>,
|
||||||
|
dirty: Vec<(u16, Range<u16>)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
struct Cell {
|
||||||
|
sym: char,
|
||||||
|
fg: Color,
|
||||||
|
bg: Color,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DrawBuf {
|
||||||
|
pub fn new(rect: Rect) -> Self {
|
||||||
|
DrawBuf {
|
||||||
|
rect,
|
||||||
|
buffer: vec![
|
||||||
|
Cell {
|
||||||
|
sym: ' ',
|
||||||
|
fg: Color::Reset,
|
||||||
|
bg: Color::Reset
|
||||||
|
};
|
||||||
|
(rect.w * rect.h) as usize
|
||||||
|
],
|
||||||
|
dirty: (0..rect.h).map(|row| (row, 0..rect.w)).collect(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn draw(&mut self, w: &mut Screen) -> Result<()> {
|
||||||
|
for (row, range) in self.dirty.drain(..) {
|
||||||
|
queue!(w, MoveTo(row, range.start))?;
|
||||||
|
for i in range {
|
||||||
|
let idx = row * self.rect.w + i;
|
||||||
|
let cell = &self.buffer[idx as usize];
|
||||||
|
queue!(w, SetForegroundColor(cell.fg), SetBackgroundColor(cell.bg),)?;
|
||||||
|
println!("{}", cell.sym);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
//! UI module
|
//! UI module
|
||||||
|
|
||||||
|
mod drawbuf;
|
||||||
mod table;
|
mod table;
|
||||||
mod tabs;
|
mod tabs;
|
||||||
mod widget;
|
mod widget;
|
||||||
|
@ -11,15 +12,16 @@ use std::time::Duration;
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use chrono::Local;
|
use chrono::Local;
|
||||||
use crossterm::{
|
use crossterm::{
|
||||||
cursor,
|
cursor::{self, MoveTo},
|
||||||
event::{self, Event, KeyCode, KeyEvent},
|
event::{self, Event, KeyCode, KeyEvent},
|
||||||
style::{self, Color},
|
style::{self, Color, SetBackgroundColor, SetForegroundColor},
|
||||||
terminal::{self, ClearType},
|
terminal::{self, Clear, ClearType},
|
||||||
};
|
};
|
||||||
use tokio::time;
|
use tokio::time;
|
||||||
|
|
||||||
use crate::ExitSender;
|
use crate::ExitSender;
|
||||||
|
|
||||||
|
use self::drawbuf::DrawBuf;
|
||||||
use self::table::Table;
|
use self::table::Table;
|
||||||
use self::tabs::Tabs;
|
use self::tabs::Tabs;
|
||||||
use self::widget::Widget;
|
use self::widget::Widget;
|
||||||
|
@ -29,13 +31,14 @@ const FRAME_DURATION: Duration = Duration::from_millis(20);
|
||||||
/// Type alias for the screen object we're drawing to
|
/// Type alias for the screen object we're drawing to
|
||||||
pub type Screen = Stdout;
|
pub type Screen = Stdout;
|
||||||
|
|
||||||
/// X Y W H
|
/// Rectangle
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
|
#[allow(missing_docs)]
|
||||||
pub struct Rect {
|
pub struct Rect {
|
||||||
x: u16,
|
pub x: u16,
|
||||||
y: u16,
|
pub y: u16,
|
||||||
w: u16,
|
pub w: u16,
|
||||||
h: u16
|
pub h: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Rect {
|
impl Rect {
|
||||||
|
@ -50,6 +53,10 @@ 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 (term_width, term_height) = terminal::size()?;
|
||||||
|
let bounds = Rect::new(0, 0, term_width, term_height);
|
||||||
|
let mut drawbuf = DrawBuf::new(bounds);
|
||||||
|
|
||||||
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()]);
|
||||||
|
@ -60,19 +67,20 @@ pub async fn run_ui(mut w: Stdout, exit: ExitSender) -> Result<()> {
|
||||||
loop {
|
loop {
|
||||||
queue!(
|
queue!(
|
||||||
w,
|
w,
|
||||||
style::SetBackgroundColor(Color::Reset),
|
SetBackgroundColor(Color::Reset),
|
||||||
style::SetForegroundColor(Color::Reset),
|
SetForegroundColor(Color::Reset),
|
||||||
terminal::Clear(ClearType::All),
|
Clear(ClearType::All),
|
||||||
cursor::MoveTo(0, 0),
|
MoveTo(0, 0),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let now = Local::now();
|
// let now = Local::now();
|
||||||
println!("time {}", now);
|
// println!("time {}", now);
|
||||||
|
|
||||||
let (term_width, term_height) = terminal::size()?;
|
let (term_width, term_height) = terminal::size()?;
|
||||||
let bounds = Rect::new(5, 5, term_width - 10, term_height - 10);
|
let bounds = Rect::new(5, 5, term_width - 10, term_height - 10);
|
||||||
// table.draw(&mut w, bounds)?;
|
// table.draw(&mut w, bounds)?;
|
||||||
tabs.draw(&mut w, bounds)?;
|
// tabs.draw(&mut w, bounds)?;
|
||||||
|
drawbuf.draw(&mut w)?;
|
||||||
w.flush()?;
|
w.flush()?;
|
||||||
|
|
||||||
// approx 60fps
|
// approx 60fps
|
||||||
|
|
|
@ -7,7 +7,7 @@ use crossterm::{
|
||||||
style::{self, Color},
|
style::{self, Color},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{Rect, Screen, Widget};
|
use super::{DrawBuf, Rect, Screen, Widget};
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct Table {
|
pub struct Table {
|
||||||
|
@ -45,7 +45,7 @@ impl Widget for Table {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw(&self, w: &mut Screen, rect: Rect) -> Result<()> {
|
fn draw(&self, buf: &mut DrawBuf, rect: Rect) -> Result<()> {
|
||||||
if !self.rows.is_empty() {
|
if !self.rows.is_empty() {
|
||||||
let mut columns = Vec::new();
|
let mut columns = Vec::new();
|
||||||
for row in self.rows.iter() {
|
for row in self.rows.iter() {
|
||||||
|
@ -59,20 +59,20 @@ impl Widget for Table {
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i, row) in self.rows.iter().enumerate() {
|
for (i, row) in self.rows.iter().enumerate() {
|
||||||
queue!(w, cursor::MoveTo(rect.x, rect.y + i as u16))?;
|
// queue!(w, cursor::MoveTo(rect.x, rect.y + i as u16))?;
|
||||||
if let Some(v) = self.selected_row {
|
if let Some(v) = self.selected_row {
|
||||||
if v == i as u16 {
|
if v == i as u16 {
|
||||||
queue!(
|
// queue!(
|
||||||
w,
|
// w,
|
||||||
style::SetBackgroundColor(Color::White),
|
// style::SetBackgroundColor(Color::White),
|
||||||
style::SetForegroundColor(Color::Black)
|
// style::SetForegroundColor(Color::Black)
|
||||||
)?;
|
// )?;
|
||||||
} else {
|
} else {
|
||||||
queue!(
|
// queue!(
|
||||||
w,
|
// w,
|
||||||
style::SetForegroundColor(Color::White),
|
// style::SetForegroundColor(Color::White),
|
||||||
style::SetBackgroundColor(Color::Black)
|
// style::SetBackgroundColor(Color::Black)
|
||||||
)?;
|
// )?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let mut s = String::with_capacity(rect.w as usize);
|
let mut s = String::with_capacity(rect.w as usize);
|
||||||
|
@ -89,20 +89,20 @@ impl Widget for Table {
|
||||||
}
|
}
|
||||||
|
|
||||||
let d = "\u{b7}".repeat(rect.w as usize);
|
let d = "\u{b7}".repeat(rect.w as usize);
|
||||||
queue!(
|
// queue!(
|
||||||
w,
|
// w,
|
||||||
style::SetBackgroundColor(Color::Black),
|
// style::SetBackgroundColor(Color::Black),
|
||||||
style::SetForegroundColor(Color::White)
|
// style::SetForegroundColor(Color::White)
|
||||||
)?;
|
// )?;
|
||||||
for j in self.rows.len() as u16..rect.h {
|
for j in self.rows.len() as u16..rect.h {
|
||||||
queue!(w, cursor::MoveTo(rect.x, rect.y + j))?;
|
// queue!(w, cursor::MoveTo(rect.x, rect.y + j))?;
|
||||||
println!("{}", d);
|
println!("{}", d);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let msg = "Nothing in this table!";
|
let msg = "Nothing in this table!";
|
||||||
let x = rect.x + (rect.w - msg.len() as u16) / 2;
|
let x = rect.x + (rect.w - msg.len() as u16) / 2;
|
||||||
let y = rect.y + rect.h / 2;
|
let y = rect.y + rect.h / 2;
|
||||||
queue!(w, cursor::MoveTo(x, y))?;
|
// queue!(w, cursor::MoveTo(x, y))?;
|
||||||
println!("{}", msg);
|
println!("{}", msg);
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -4,7 +4,7 @@ use std::io::Write;
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use crossterm::{cursor::MoveTo, event::Event};
|
use crossterm::{cursor::MoveTo, event::Event};
|
||||||
|
|
||||||
use super::{Rect, Screen, Widget};
|
use super::{DrawBuf, Rect, Screen, Widget};
|
||||||
|
|
||||||
pub struct Tabs {
|
pub struct Tabs {
|
||||||
id_incr: usize,
|
id_incr: usize,
|
||||||
|
@ -35,15 +35,15 @@ impl Tabs {
|
||||||
impl Widget for Tabs {
|
impl Widget for Tabs {
|
||||||
fn update(&mut self, event: Option<Event>) {}
|
fn update(&mut self, event: Option<Event>) {}
|
||||||
|
|
||||||
fn draw(&self, w: &mut Screen, rect: Rect) -> Result<()> {
|
fn draw(&self, buf: &mut DrawBuf, rect: Rect) -> Result<()> {
|
||||||
queue!(w, MoveTo(rect.x, rect.y))?;
|
// queue!(w, MoveTo(rect.x, rect.y))?;
|
||||||
for (id, name) in self.names.iter() {
|
for (id, name) in self.names.iter() {
|
||||||
println!(" {} ", name);
|
println!(" {} ", name);
|
||||||
}
|
}
|
||||||
|
|
||||||
let new_rect = Rect::new(rect.x, rect.y + 1, rect.w, rect.h - 1);
|
let new_rect = Rect::new(rect.x, rect.y + 1, rect.w, rect.h - 1);
|
||||||
if let Some(widget) = self.contents.get(&self.active_id) {
|
if let Some(widget) = self.contents.get(&self.active_id) {
|
||||||
widget.draw(w, new_rect)?;
|
widget.draw(buf, new_rect)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -3,14 +3,14 @@ use std::io::Write;
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use crossterm::event::Event;
|
use crossterm::event::Event;
|
||||||
|
|
||||||
use super::{Rect, Screen};
|
use super::{DrawBuf, Rect, Screen};
|
||||||
|
|
||||||
pub trait Widget {
|
pub trait Widget {
|
||||||
/// Updates the widget given an event
|
/// Updates the widget given an event
|
||||||
fn update(&mut self, event: Option<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, buf: &mut DrawBuf, rect: Rect) -> Result<()>;
|
||||||
|
|
||||||
/// Invalidates this UI element, queueing it for redraw
|
/// Invalidates this UI element, queueing it for redraw
|
||||||
fn invalidate(&mut self);
|
fn invalidate(&mut self);
|
||||||
|
|
Loading…
Reference in a new issue