playing around with ui

This commit is contained in:
Michael Zhang 2021-03-01 03:35:14 -06:00
parent 07846f996f
commit 84cd7ae0f4
Signed by: michael
GPG key ID: BDA47A31A3C8EE6B
2 changed files with 38 additions and 108 deletions

View file

@ -1,95 +0,0 @@
use std::io;
use std::sync::mpsc;
use std::sync::{
atomic::{AtomicBool, Ordering},
Arc,
};
use std::thread;
use std::time::Duration;
use termion::event::Key;
use termion::input::TermRead;
pub enum Event<I> {
Input(I),
Tick,
}
/// A small event handler that wrap termion input and tick events. Each event
/// type is handled in its own thread and returned to a common `Receiver`
pub struct Events {
rx: mpsc::Receiver<Event<Key>>,
input_handle: thread::JoinHandle<()>,
ignore_exit_key: Arc<AtomicBool>,
tick_handle: thread::JoinHandle<()>,
}
#[derive(Debug, Clone, Copy)]
pub struct Config {
pub exit_key: Key,
pub tick_rate: Duration,
}
impl Default for Config {
fn default() -> Config {
Config {
exit_key: Key::Char('q'),
tick_rate: Duration::from_millis(250),
}
}
}
impl Events {
pub fn new() -> Events {
Events::with_config(Config::default())
}
pub fn with_config(config: Config) -> Events {
let (tx, rx) = mpsc::channel();
let ignore_exit_key = Arc::new(AtomicBool::new(false));
let input_handle = {
let tx = tx.clone();
let ignore_exit_key = ignore_exit_key.clone();
thread::spawn(move || {
let stdin = io::stdin();
for evt in stdin.keys() {
if let Ok(key) = evt {
if let Err(err) = tx.send(Event::Input(key)) {
eprintln!("{}", err);
return;
}
if !ignore_exit_key.load(Ordering::Relaxed) && key == config.exit_key {
return;
}
}
}
})
};
let tick_handle = {
thread::spawn(move || loop {
if tx.send(Event::Tick).is_err() {
break;
}
thread::sleep(config.tick_rate);
})
};
Events {
rx,
ignore_exit_key,
input_handle,
tick_handle,
}
}
pub fn next(&self) -> Result<Event<Key>, mpsc::RecvError> {
self.rx.recv()
}
pub fn disable_exit_key(&mut self) {
self.ignore_exit_key.store(true, Ordering::Relaxed);
}
pub fn enable_exit_key(&mut self) {
self.ignore_exit_key.store(false, Ordering::Relaxed);
}
}

View file

@ -14,6 +14,7 @@ use tokio::{sync::mpsc, time};
use tui::{
backend::CrosstermBackend,
layout::{Constraint, Direction, Layout},
style::{Color, Modifier, Style},
text::Spans,
widgets::*,
Terminal,
@ -34,23 +35,47 @@ pub async fn run_ui(mut stdout: Stdout, exit_tx: mpsc::Sender<()>) -> Result<()>
let chunks = Layout::default()
.direction(Direction::Vertical)
.margin(0)
.constraints(
[
Constraint::Percentage(10),
Constraint::Percentage(80),
Constraint::Percentage(10),
]
.as_ref(),
)
.constraints([
Constraint::Length(1),
Constraint::Max(5000),
// Constraint::Percentage(10),
// Constraint::Percentage(80),
// Constraint::Percentage(10),
])
.split(f.size());
let block = Block::default().title("Block").borders(Borders::NONE);
f.render_widget(block, chunks[0]);
let block = Block::default().title("Block 2").borders(Borders::ALL);
f.render_widget(block, chunks[1]);
let chunks2 = Layout::default()
.direction(Direction::Horizontal)
.margin(0)
.constraints([
Constraint::Length(20),
Constraint::Max(5000),
//
])
.split(chunks[1]);
// this is the title bar
let titles = vec!["hellosu"].into_iter().map(Spans::from).collect();
let tabs = Tabs::new(titles);
f.render_widget(tabs, chunks[2]);
f.render_widget(tabs, chunks[0]);
// TODO: check active tab
let items = [
ListItem::new("Osu"),
ListItem::new("Game").style(Style::default().add_modifier(Modifier::BOLD)),
];
let dirlist = List::new(items)
.block(Block::default().title("List").borders(Borders::ALL))
.style(Style::default().fg(Color::White))
.highlight_style(Style::default().add_modifier(Modifier::ITALIC))
.highlight_symbol(">>");
f.render_widget(dirlist, chunks2[0]);
let block = Block::default().title("Block").borders(Borders::ALL);
f.render_widget(block, chunks2[1]);
// let block = Block::default().title("Block 2").borders(Borders::ALL);
// f.render_widget(block, chunks[1]);
})?;
let event = if event::poll(FRAME_DURATION)? {