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

View File

@ -38,7 +38,7 @@ anyhow = "1.0.40"
backtrace = "0.3.59"
battery = "0.7.8"
chrono = "0.4.19"
crossterm = "0.18.2"
crossterm = "0.20.0"
ctrlc = { version = "3.1.9", features = ["termination"] }
clap = "2.33"
cfg-if = "1.0"
@ -55,7 +55,7 @@ serde = { version = "1.0.125", features = ["derive"] }
sysinfo = "0.18.2"
thiserror = "1.0.24"
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"
unicode-segmentation = "1.7.1"
unicode-width = "0.1"

View File

@ -8,7 +8,7 @@ use bottom::{canvas, constants::*, data_conversion::*, options::*, *};
use std::{
boxed::Box,
io::{stdout, Write},
io::stdout,
panic,
sync::{
atomic::{AtomicBool, Ordering},
@ -96,7 +96,7 @@ fn main() -> Result<()> {
};
// 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(
sender,
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)) {
match recv {
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;
}
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::MouseInput(event) => match handle_mouse_event(event, &mut app) {
EventResult::Quit => {
break;
}
handle_force_redraws(&mut app);
}
BottomEvent::MouseInput(event) => {
handle_mouse_event(event, &mut app);
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)?;
}
EventResult::Continue => {}
},
BottomEvent::Update(data) => {
app.data_collection.eat_data(data);
@ -220,6 +234,8 @@ fn main() -> Result<()> {
app.canvas_data.battery_data =
convert_battery_harvest(&app.data_collection);
}
try_drawing(&mut terminal, &mut app, &mut painter)?;
}
}
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...
*thread_termination_lock.lock().unwrap() = true;
thread_termination_cvar.notify_all();
cleanup_terminal(&mut terminal)?;
Ok(())

View File

@ -20,7 +20,10 @@ use std::{
};
use crossterm::{
event::{poll, read, DisableMouseCapture, Event, KeyCode, KeyEvent, KeyModifiers, MouseEvent},
event::{
read, DisableMouseCapture, Event, KeyCode, KeyEvent, KeyModifiers, MouseButton, MouseEvent,
MouseEventKind,
},
execute,
style::Print,
terminal::{disable_raw_mode, LeaveAlternateScreen},
@ -71,29 +74,36 @@ pub enum ThreadControlEvent {
UpdateUpdateTime(u64),
}
pub fn handle_mouse_event(event: MouseEvent, app: &mut AppState) {
match event {
MouseEvent::ScrollUp(_x, _y, _modifiers) => app.handle_scroll_up(),
MouseEvent::ScrollDown(_x, _y, _modifiers) => app.handle_scroll_down(),
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 enum EventResult {
Quit,
Redraw,
Continue,
}
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>,
) -> bool {
) -> EventResult {
// debug!("KeyEvent: {:?}", event);
// 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() {
// Required catch for searching - otherwise you couldn't search with q.
if event.code == KeyCode::Char('q') && !app.is_in_search_widget() {
return true;
return EventResult::Quit;
}
match event.code {
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(6) => app.toggle_sort(),
KeyCode::F(9) => app.start_killing_process(),
_ => {}
_ => {
return EventResult::Continue;
}
}
} else {
// Otherwise, track the modifier as well...
@ -140,7 +152,7 @@ pub fn handle_key_event_or_break(
}
} else if let KeyModifiers::CONTROL = event.modifiers {
if event.code == KeyCode::Char('c') {
return true;
return EventResult::Quit;
}
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
// are hard to iter while truncating last (eloquently).
// KeyCode::Backspace => app.skip_word_backspace(),
_ => {}
_ => {
return EventResult::Continue;
}
}
} else if let KeyModifiers::SHIFT = event.modifiers {
match event.code {
@ -175,12 +189,14 @@ pub fn handle_key_event_or_break(
KeyCode::Up => app.move_widget_selection(&WidgetDirection::Up),
KeyCode::Down => app.move_widget_selection(&WidgetDirection::Down),
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>> {
@ -300,7 +316,7 @@ pub fn panic_hook(panic_info: &PanicInfo<'_>) {
.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
// if we eventually get widget-specific redrawing!
if app.proc_state.force_update_all {
@ -607,25 +623,30 @@ pub fn create_input_thread(
break;
}
}
if let Ok(poll) = poll(Duration::from_millis(20)) {
if poll {
if let Ok(event) = read() {
if let Event::Key(key) = event {
if Instant::now().duration_since(keyboard_timer).as_millis() >= 20 {
if sender.send(BottomEvent::KeyInput(key)).is_err() {
break;
}
keyboard_timer = Instant::now();
if let Ok(event) = read() {
match event {
Event::Key(event) => {
if Instant::now().duration_since(keyboard_timer).as_millis() >= 20 {
if sender.send(BottomEvent::KeyInput(event)).is_err() {
break;
}
} else if let Event::Mouse(mouse) = event {
keyboard_timer = Instant::now();
}
}
Event::Mouse(event) => match &event.kind {
MouseEventKind::Drag(_) => {}
MouseEventKind::Moved => {}
_ => {
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;
}
mouse_timer = Instant::now();
}
}
}
},
Event::Resize(_, _) => {}
}
}
}

View File

@ -16,9 +16,6 @@ pub enum BottomError {
/// An error when the heim library encounters a problem.
#[error("Error caused by Heim, {0}")]
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.
#[error("Generic error, {0}")]
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 {
fn from(err: std::num::ParseIntError) -> Self {