playing around with ui
This commit is contained in:
parent
07846f996f
commit
84cd7ae0f4
2 changed files with 38 additions and 108 deletions
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -14,6 +14,7 @@ use tokio::{sync::mpsc, time};
|
||||||
use tui::{
|
use tui::{
|
||||||
backend::CrosstermBackend,
|
backend::CrosstermBackend,
|
||||||
layout::{Constraint, Direction, Layout},
|
layout::{Constraint, Direction, Layout},
|
||||||
|
style::{Color, Modifier, Style},
|
||||||
text::Spans,
|
text::Spans,
|
||||||
widgets::*,
|
widgets::*,
|
||||||
Terminal,
|
Terminal,
|
||||||
|
@ -34,23 +35,47 @@ pub async fn run_ui(mut stdout: Stdout, exit_tx: mpsc::Sender<()>) -> Result<()>
|
||||||
let chunks = Layout::default()
|
let chunks = Layout::default()
|
||||||
.direction(Direction::Vertical)
|
.direction(Direction::Vertical)
|
||||||
.margin(0)
|
.margin(0)
|
||||||
.constraints(
|
.constraints([
|
||||||
[
|
Constraint::Length(1),
|
||||||
Constraint::Percentage(10),
|
Constraint::Max(5000),
|
||||||
Constraint::Percentage(80),
|
// Constraint::Percentage(10),
|
||||||
Constraint::Percentage(10),
|
// Constraint::Percentage(80),
|
||||||
]
|
// Constraint::Percentage(10),
|
||||||
.as_ref(),
|
])
|
||||||
)
|
|
||||||
.split(f.size());
|
.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 titles = vec!["hellosu"].into_iter().map(Spans::from).collect();
|
||||||
let tabs = Tabs::new(titles);
|
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)? {
|
let event = if event::poll(FRAME_DURATION)? {
|
||||||
|
|
Loading…
Reference in a new issue