deps: Update crossterm + tui-rs, along with event handling code

This commit is contained in:
ClementTsang 2021-08-13 22:21:55 -04:00
parent f73ea0da36
commit 5749c32bd5
5 changed files with 123 additions and 80 deletions

50
Cargo.lock generated
View File

@ -144,7 +144,7 @@ dependencies = [
"event-listener", "event-listener",
"futures-lite", "futures-lite",
"once_cell", "once_cell",
"signal-hook", "signal-hook 0.1.17",
"winapi", "winapi",
] ]
@ -454,25 +454,25 @@ dependencies = [
[[package]] [[package]]
name = "crossterm" name = "crossterm"
version = "0.18.2" version = "0.20.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4e86d73f2a0b407b5768d10a8c720cf5d2df49a9efc10ca09176d201ead4b7fb" checksum = "c0ebde6a9dd5e331cd6c6f48253254d117642c31653baa475e394657c59c1f7d"
dependencies = [ dependencies = [
"bitflags", "bitflags",
"crossterm_winapi", "crossterm_winapi",
"lazy_static",
"libc", "libc",
"mio", "mio",
"parking_lot", "parking_lot",
"signal-hook", "signal-hook 0.3.9",
"signal-hook-mio",
"winapi", "winapi",
] ]
[[package]] [[package]]
name = "crossterm_winapi" name = "crossterm_winapi"
version = "0.6.2" version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2265c3f8e080075d9b6417aa72293fc71662f34b4af2612d8d1b074d29510db" checksum = "3a6966607622438301997d3dac0d2f6e9a90c68bb6bc1785ea98456ab93c0507"
dependencies = [ dependencies = [
"winapi", "winapi",
] ]
@ -1333,20 +1333,40 @@ dependencies = [
[[package]] [[package]]
name = "signal-hook" name = "signal-hook"
version = "0.1.16" version = "0.1.17"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "604508c1418b99dfe1925ca9224829bb2a8a9a04dda655cc01fcad46f4ab05ed" checksum = "7e31d442c16f047a671b5a71e2161d6e68814012b7f5379d269ebd915fac2729"
dependencies = [ dependencies = [
"libc", "libc",
"mio",
"signal-hook-registry", "signal-hook-registry",
] ]
[[package]] [[package]]
name = "signal-hook-registry" name = "signal-hook"
version = "1.2.2" version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce32ea0c6c56d5eacaeb814fbed9960547021d3edd010ded1425f180536b20ab" checksum = "470c5a6397076fae0094aaf06a08e6ba6f37acb77d3b1b91ea92b4d6c8650c39"
dependencies = [
"libc",
"signal-hook-registry",
]
[[package]]
name = "signal-hook-mio"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "29fd5867f1c4f2c5be079aee7a2adf1152ebb04a4bc4d341f504b7dece607ed4"
dependencies = [
"libc",
"mio",
"signal-hook 0.3.9",
]
[[package]]
name = "signal-hook-registry"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0"
dependencies = [ dependencies = [
"libc", "libc",
] ]
@ -1483,9 +1503,9 @@ checksum = "a7f741b240f1a48843f9b8e0444fb55fb2a4ff67293b50a9179dfd5ea67f8d41"
[[package]] [[package]]
name = "tui" name = "tui"
version = "0.14.0" version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ced152a8e9295a5b168adc254074525c17ac4a83c90b2716274cc38118bddc9" checksum = "39c8ce4e27049eed97cfa363a5048b09d995e209994634a0efc26a14ab6c0c23"
dependencies = [ dependencies = [
"bitflags", "bitflags",
"cassowary", "cassowary",

View File

@ -38,7 +38,7 @@ anyhow = "1.0.40"
backtrace = "0.3.59" backtrace = "0.3.59"
battery = "0.7.8" battery = "0.7.8"
chrono = "0.4.19" chrono = "0.4.19"
crossterm = "0.18.2" crossterm = "0.20.0"
ctrlc = { version = "3.1.9", features = ["termination"] } ctrlc = { version = "3.1.9", features = ["termination"] }
clap = "2.33" clap = "2.33"
cfg-if = "1.0" cfg-if = "1.0"
@ -55,7 +55,7 @@ serde = { version = "1.0.125", features = ["derive"] }
sysinfo = "0.18.2" sysinfo = "0.18.2"
thiserror = "1.0.24" thiserror = "1.0.24"
toml = "0.5.8" toml = "0.5.8"
tui = { version = "0.14.0", features = ["crossterm"], default-features = false } tui = { version = "0.16.0", features = ["crossterm"], default-features = false }
typed-builder = "0.9.0" typed-builder = "0.9.0"
unicode-segmentation = "1.7.1" unicode-segmentation = "1.7.1"
unicode-width = "0.1" unicode-width = "0.1"

View File

@ -8,7 +8,7 @@ use bottom::{canvas, constants::*, data_conversion::*, options::*, *};
use std::{ use std::{
boxed::Box, boxed::Box,
io::{stdout, Write}, io::stdout,
panic, panic,
sync::{ sync::{
atomic::{AtomicBool, Ordering}, atomic::{AtomicBool, Ordering},
@ -96,7 +96,7 @@ fn main() -> Result<()> {
}; };
// Event loop // Event loop
let (collection_thread_ctrl_sender, collection_thread_ctrl_receiver) = mpsc::channel(); let (collection_sender, collection_thread_ctrl_receiver) = mpsc::channel();
let _collection_thread = create_collection_thread( let _collection_thread = create_collection_thread(
sender, sender,
collection_thread_ctrl_receiver, collection_thread_ctrl_receiver,
@ -131,15 +131,29 @@ fn main() -> Result<()> {
if let Ok(recv) = receiver.recv_timeout(Duration::from_millis(TICK_RATE_IN_MILLISECONDS)) { if let Ok(recv) = receiver.recv_timeout(Duration::from_millis(TICK_RATE_IN_MILLISECONDS)) {
match recv { match recv {
BottomEvent::KeyInput(event) => { BottomEvent::KeyInput(event) => {
if handle_key_event_or_break(event, &mut app, &collection_thread_ctrl_sender) { match handle_key_event(event, &mut app, &collection_sender) {
EventResult::Quit => {
break; break;
} }
handle_force_redraws(&mut app); EventResult::Redraw => {
// TODO: Be even more granular! Maybe the event triggered no change, then we shouldn't redraw.
force_redraw(&mut app);
try_drawing(&mut terminal, &mut app, &mut painter)?;
} }
BottomEvent::MouseInput(event) => { EventResult::Continue => {}
handle_mouse_event(event, &mut app);
handle_force_redraws(&mut app);
} }
}
BottomEvent::MouseInput(event) => match handle_mouse_event(event, &mut app) {
EventResult::Quit => {
break;
}
EventResult::Redraw => {
// TODO: Be even more granular! Maybe the event triggered no change, then we shouldn't redraw.
force_redraw(&mut app);
try_drawing(&mut terminal, &mut app, &mut painter)?;
}
EventResult::Continue => {}
},
BottomEvent::Update(data) => { BottomEvent::Update(data) => {
app.data_collection.eat_data(data); app.data_collection.eat_data(data);
@ -220,6 +234,8 @@ fn main() -> Result<()> {
app.canvas_data.battery_data = app.canvas_data.battery_data =
convert_battery_harvest(&app.data_collection); convert_battery_harvest(&app.data_collection);
} }
try_drawing(&mut terminal, &mut app, &mut painter)?;
} }
} }
BottomEvent::Clean => { BottomEvent::Clean => {
@ -228,17 +244,11 @@ fn main() -> Result<()> {
} }
} }
} }
// TODO: [OPT] Should not draw if no change (ie: scroll max)
try_drawing(&mut terminal, &mut app, &mut painter)?;
} }
// I think doing it in this order is safe... // I think doing it in this order is safe...
*thread_termination_lock.lock().unwrap() = true; *thread_termination_lock.lock().unwrap() = true;
thread_termination_cvar.notify_all(); thread_termination_cvar.notify_all();
cleanup_terminal(&mut terminal)?; cleanup_terminal(&mut terminal)?;
Ok(()) Ok(())

View File

@ -20,7 +20,10 @@ use std::{
}; };
use crossterm::{ use crossterm::{
event::{poll, read, DisableMouseCapture, Event, KeyCode, KeyEvent, KeyModifiers, MouseEvent}, event::{
read, DisableMouseCapture, Event, KeyCode, KeyEvent, KeyModifiers, MouseButton, MouseEvent,
MouseEventKind,
},
execute, execute,
style::Print, style::Print,
terminal::{disable_raw_mode, LeaveAlternateScreen}, terminal::{disable_raw_mode, LeaveAlternateScreen},
@ -71,29 +74,36 @@ pub enum ThreadControlEvent {
UpdateUpdateTime(u64), UpdateUpdateTime(u64),
} }
pub fn handle_mouse_event(event: MouseEvent, app: &mut AppState) { pub enum EventResult {
match event { Quit,
MouseEvent::ScrollUp(_x, _y, _modifiers) => app.handle_scroll_up(), Redraw,
MouseEvent::ScrollDown(_x, _y, _modifiers) => app.handle_scroll_down(), Continue,
MouseEvent::Down(button, x, y, _modifiers) => {
if !app.app_config_fields.disable_click {
match button {
crossterm::event::MouseButton::Left => {
// Trigger left click widget activity
app.on_left_mouse_up(x, y);
}
crossterm::event::MouseButton::Right => {}
_ => {}
}
}
}
_ => {}
};
} }
pub fn handle_key_event_or_break( pub fn handle_mouse_event(event: MouseEvent, app: &mut AppState) -> EventResult {
match event.kind {
MouseEventKind::Down(button) => match button {
MouseButton::Left => {
app.on_left_mouse_up(event.column, event.row);
EventResult::Redraw
}
_ => EventResult::Continue,
},
MouseEventKind::ScrollUp => {
app.handle_scroll_up();
EventResult::Redraw
}
MouseEventKind::ScrollDown => {
app.handle_scroll_down();
EventResult::Redraw
}
_ => EventResult::Continue,
}
}
pub fn handle_key_event(
event: KeyEvent, app: &mut AppState, reset_sender: &std::sync::mpsc::Sender<ThreadControlEvent>, event: KeyEvent, app: &mut AppState, reset_sender: &std::sync::mpsc::Sender<ThreadControlEvent>,
) -> bool { ) -> EventResult {
// debug!("KeyEvent: {:?}", event); // debug!("KeyEvent: {:?}", event);
// TODO: [PASTE] Note that this does NOT support some emojis like flags. This is due to us // TODO: [PASTE] Note that this does NOT support some emojis like flags. This is due to us
@ -104,7 +114,7 @@ pub fn handle_key_event_or_break(
if event.modifiers.is_empty() { if event.modifiers.is_empty() {
// Required catch for searching - otherwise you couldn't search with q. // Required catch for searching - otherwise you couldn't search with q.
if event.code == KeyCode::Char('q') && !app.is_in_search_widget() { if event.code == KeyCode::Char('q') && !app.is_in_search_widget() {
return true; return EventResult::Quit;
} }
match event.code { match event.code {
KeyCode::End => app.skip_to_last(), KeyCode::End => app.skip_to_last(),
@ -125,7 +135,9 @@ pub fn handle_key_event_or_break(
KeyCode::F(5) => app.toggle_tree_mode(), KeyCode::F(5) => app.toggle_tree_mode(),
KeyCode::F(6) => app.toggle_sort(), KeyCode::F(6) => app.toggle_sort(),
KeyCode::F(9) => app.start_killing_process(), KeyCode::F(9) => app.start_killing_process(),
_ => {} _ => {
return EventResult::Continue;
}
} }
} else { } else {
// Otherwise, track the modifier as well... // Otherwise, track the modifier as well...
@ -140,7 +152,7 @@ pub fn handle_key_event_or_break(
} }
} else if let KeyModifiers::CONTROL = event.modifiers { } else if let KeyModifiers::CONTROL = event.modifiers {
if event.code == KeyCode::Char('c') { if event.code == KeyCode::Char('c') {
return true; return EventResult::Quit;
} }
match event.code { match event.code {
@ -166,7 +178,9 @@ pub fn handle_key_event_or_break(
// Can't do now, CTRL+BACKSPACE doesn't work and graphemes // Can't do now, CTRL+BACKSPACE doesn't work and graphemes
// are hard to iter while truncating last (eloquently). // are hard to iter while truncating last (eloquently).
// KeyCode::Backspace => app.skip_word_backspace(), // KeyCode::Backspace => app.skip_word_backspace(),
_ => {} _ => {
return EventResult::Continue;
}
} }
} else if let KeyModifiers::SHIFT = event.modifiers { } else if let KeyModifiers::SHIFT = event.modifiers {
match event.code { match event.code {
@ -175,12 +189,14 @@ pub fn handle_key_event_or_break(
KeyCode::Up => app.move_widget_selection(&WidgetDirection::Up), KeyCode::Up => app.move_widget_selection(&WidgetDirection::Up),
KeyCode::Down => app.move_widget_selection(&WidgetDirection::Down), KeyCode::Down => app.move_widget_selection(&WidgetDirection::Down),
KeyCode::Char(caught_char) => app.on_char_key(caught_char), KeyCode::Char(caught_char) => app.on_char_key(caught_char),
_ => {} _ => {
return EventResult::Continue;
}
} }
} }
} }
false EventResult::Redraw
} }
pub fn read_config(config_location: Option<&str>) -> error::Result<Option<PathBuf>> { pub fn read_config(config_location: Option<&str>) -> error::Result<Option<PathBuf>> {
@ -300,7 +316,7 @@ pub fn panic_hook(panic_info: &PanicInfo<'_>) {
.unwrap(); .unwrap();
} }
pub fn handle_force_redraws(app: &mut AppState) { pub fn force_redraw(app: &mut AppState) {
// Currently we use an Option... because we might want to future-proof this // Currently we use an Option... because we might want to future-proof this
// if we eventually get widget-specific redrawing! // if we eventually get widget-specific redrawing!
if app.proc_state.force_update_all { if app.proc_state.force_update_all {
@ -607,25 +623,30 @@ pub fn create_input_thread(
break; break;
} }
} }
if let Ok(poll) = poll(Duration::from_millis(20)) {
if poll {
if let Ok(event) = read() { if let Ok(event) = read() {
if let Event::Key(key) = event { match event {
Event::Key(event) => {
if Instant::now().duration_since(keyboard_timer).as_millis() >= 20 { if Instant::now().duration_since(keyboard_timer).as_millis() >= 20 {
if sender.send(BottomEvent::KeyInput(key)).is_err() { if sender.send(BottomEvent::KeyInput(event)).is_err() {
break; break;
} }
keyboard_timer = Instant::now(); keyboard_timer = Instant::now();
} }
} else if let Event::Mouse(mouse) = event { }
Event::Mouse(event) => match &event.kind {
MouseEventKind::Drag(_) => {}
MouseEventKind::Moved => {}
_ => {
if Instant::now().duration_since(mouse_timer).as_millis() >= 20 { if Instant::now().duration_since(mouse_timer).as_millis() >= 20 {
if sender.send(BottomEvent::MouseInput(mouse)).is_err() { if sender.send(BottomEvent::MouseInput(event)).is_err() {
break; break;
} }
mouse_timer = Instant::now(); mouse_timer = Instant::now();
} }
} }
} },
Event::Resize(_, _) => {}
} }
} }
} }

View File

@ -16,9 +16,6 @@ pub enum BottomError {
/// An error when the heim library encounters a problem. /// An error when the heim library encounters a problem.
#[error("Error caused by Heim, {0}")] #[error("Error caused by Heim, {0}")]
InvalidHeim(String), InvalidHeim(String),
/// An error when the Crossterm library encounters a problem.
#[error("Error caused by Crossterm, {0}")]
CrosstermError(String),
/// An error to represent generic errors. /// An error to represent generic errors.
#[error("Generic error, {0}")] #[error("Generic error, {0}")]
GenericError(String), GenericError(String),
@ -55,11 +52,6 @@ impl From<heim::Error> for BottomError {
} }
} }
impl From<crossterm::ErrorKind> for BottomError {
fn from(err: crossterm::ErrorKind) -> Self {
BottomError::CrosstermError(err.to_string())
}
}
impl From<std::num::ParseIntError> for BottomError { impl From<std::num::ParseIntError> for BottomError {
fn from(err: std::num::ParseIntError) -> Self { fn from(err: std::num::ParseIntError) -> Self {