diff options
author | ClementTsang <cjhtsang@uwaterloo.ca> | 2021-08-23 16:50:02 -0400 |
---|---|---|
committer | ClementTsang <cjhtsang@uwaterloo.ca> | 2021-08-23 17:34:52 -0400 |
commit | 64c6d0c8984616b2b1dba32ea2fc18d46caf540a (patch) | |
tree | b0db48e9a54a9229f2de092c1c4441474e38c1fa | |
parent | e657fec2c04a1adabc7e28ff28c1292bb4c282e8 (diff) |
refactor + change: write new movement logic
-rw-r--r-- | Cargo.lock | 7 | ||||
-rw-r--r-- | Cargo.toml | 1 | ||||
-rw-r--r-- | src/app/event.rs | 27 | ||||
-rw-r--r-- | src/app/widgets/base/carousel.rs | 0 | ||||
-rw-r--r-- | src/app/widgets/base/mod.rs | 2 | ||||
-rw-r--r-- | src/app/widgets/base/scrollable.rs | 54 | ||||
-rw-r--r-- | src/app/widgets/base/text_input.rs | 139 | ||||
-rw-r--r-- | src/app/widgets/base/text_table.rs | 103 | ||||
-rw-r--r-- | src/app/widgets/base/time_graph.rs | 28 | ||||
-rw-r--r-- | src/app/widgets/basic_cpu.rs | 0 | ||||
-rw-r--r-- | src/app/widgets/basic_mem.rs | 0 | ||||
-rw-r--r-- | src/app/widgets/basic_net.rs | 0 | ||||
-rw-r--r-- | src/app/widgets/battery.rs | 31 | ||||
-rw-r--r-- | src/app/widgets/cpu.rs | 27 | ||||
-rw-r--r-- | src/app/widgets/disk.rs | 15 | ||||
-rw-r--r-- | src/app/widgets/mem.rs | 8 | ||||
-rw-r--r-- | src/app/widgets/mod.rs | 339 | ||||
-rw-r--r-- | src/app/widgets/net.rs | 39 | ||||
-rw-r--r-- | src/app/widgets/process.rs | 212 | ||||
-rw-r--r-- | src/app/widgets/temp.rs | 15 | ||||
-rw-r--r-- | src/bin/main.rs | 4 | ||||
-rw-r--r-- | src/lib.rs | 8 |
22 files changed, 900 insertions, 159 deletions
@@ -251,6 +251,7 @@ dependencies = [ "fxhash", "heim", "indexmap", + "indextree", "itertools", "libc", "log", @@ -883,6 +884,12 @@ dependencies = [ ] [[package]] +name = "indextree" +version = "4.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "990980c3d268c9b99df35e813eca2b8d1ee08606f6d2bb325edbd0b0c68f9ffe" + +[[package]] name = "instant" version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -48,6 +48,7 @@ futures = "0.3.14" futures-timer = "3.0.2" fxhash = "0.2.1" indexmap = "1.6.2" +indextree = "4.3.1" itertools = "0.10.0" once_cell = "1.5.2" regex = "1.5.4" diff --git a/src/app/event.rs b/src/app/event.rs index 79efd9f5..d51a490e 100644 --- a/src/app/event.rs +++ b/src/app/event.rs @@ -1,11 +1,30 @@ use std::time::{Duration, Instant}; +const MAX_TIMEOUT: Duration = Duration::from_millis(400); + +/// The results of handling some user input event, like a mouse or key event, signifying what +/// the program should then do next. pub enum EventResult { + /// Kill the program. Quit, + + /// Trigger a redraw. Redraw, - Continue, + + /// Don't trigger a redraw. + NoRedraw, +} + +/// How a widget should handle a widget selection request. +pub enum SelectionAction { + /// This event occurs if the widget internally handled the selection action. + Handled, + + /// This event occurs if the widget did not handle the selection action; the caller must handle it. + NotHandled, } +/// The states a [`MultiKey`] can be in. enum MultiKeyState { /// Currently not waiting on any next input. Idle, @@ -36,16 +55,14 @@ pub enum MultiKeyResult { pub struct MultiKey { state: MultiKeyState, pattern: Vec<char>, - timeout: Duration, } impl MultiKey { /// Creates a new [`MultiKey`] with a given pattern and timeout. - pub fn register(pattern: Vec<char>, timeout: Duration) -> Self { + pub fn register(pattern: Vec<char>) -> Self { Self { state: MultiKeyState::Idle, pattern, - timeout, } } @@ -81,7 +98,7 @@ impl MultiKey { trigger_instant, checked_index, } => { - if trigger_instant.elapsed() > self.timeout { + if trigger_instant.elapsed() > MAX_TIMEOUT { // Just reset and recursively call (putting it into Idle). self.reset(); self.input(c) diff --git a/src/app/widgets/base/carousel.rs b/src/app/widgets/base/carousel.rs new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/src/app/widgets/base/carousel.rs diff --git a/src/app/widgets/base/mod.rs b/src/app/widgets/base/mod.rs index 2a833b77..7176c1cc 100644 --- a/src/app/widgets/base/mod.rs +++ b/src/app/widgets/base/mod.rs @@ -1,4 +1,4 @@ -//! A collection of basic widgets. +//! A collection of basic components. pub mod text_table; pub use text_table::TextTable; diff --git a/src/app/widgets/base/scrollable.rs b/src/app/widgets/base/scrollable.rs index 675dc558..4606b02b 100644 --- a/src/app/widgets/base/scrollable.rs +++ b/src/app/widgets/base/scrollable.rs @@ -1,11 +1,9 @@ -use std::time::Duration; - use crossterm::event::{KeyEvent, KeyModifiers, MouseButton, MouseEvent}; use tui::{layout::Rect, widgets::TableState}; use crate::app::{ event::{EventResult, MultiKey, MultiKeyResult}, - Widget, + Component, }; pub enum ScrollDirection { @@ -36,7 +34,7 @@ impl Scrollable { scroll_direction: ScrollDirection::Down, num_items, tui_state: TableState::default(), - gg_manager: MultiKey::register(vec!['g', 'g'], Duration::from_millis(400)), + gg_manager: MultiKey::register(vec!['g', 'g']), // TODO: Use a static arrayvec bounds: Rect::default(), } } @@ -79,7 +77,7 @@ impl Scrollable { EventResult::Redraw } else { - EventResult::Continue + EventResult::NoRedraw } } @@ -90,7 +88,7 @@ impl Scrollable { EventResult::Redraw } else { - EventResult::Continue + EventResult::NoRedraw } } @@ -104,7 +102,7 @@ impl Scrollable { EventResult::Redraw } else { - EventResult::Continue + EventResult::NoRedraw } } else { self.update_index(new_index); @@ -121,18 +119,28 @@ impl Scrollable { EventResult::Redraw } else { - EventResult::Continue + EventResult::NoRedraw } } else { self.update_index(new_index); EventResult::Redraw } } -} -impl Widget for Scrollable { - type UpdateData = usize; + pub fn update_num_items(&mut self, num_items: usize) { + self.num_items = num_items; + + if num_items <= self.current_index { + self.current_index = num_items - 1; + } + + if num_items <= self.previous_index { + self.previous_index = num_items - 1; + } + } +} +impl Component for Scrollable { fn handle_key_event(&mut self, event: KeyEvent) -> EventResult { use crossterm::event::KeyCode::{Char, Down, Up}; @@ -144,14 +152,14 @@ impl Widget for Scrollable { Char('k') => self.move_up(1), Char('g') => match self.gg_manager.input('g') { MultiKeyResult::Completed => self.skip_to_first(), - MultiKeyResult::Accepted => EventResult::Continue, - MultiKeyResult::Rejected => EventResult::Continue, + MultiKeyResult::Accepted => EventResult::NoRedraw, + MultiKeyResult::Rejected => EventResult::NoRedraw, }, Char('G') => self.skip_to_last(), - _ => EventResult::Continue, + _ => EventResult::NoRedraw, } } else { - EventResult::Continue + EventResult::NoRedraw } } @@ -176,23 +184,11 @@ impl Widget for Scrollable { } } - EventResult::Continue + EventResult::NoRedraw } crossterm::event::MouseEventKind::ScrollDown => self.move_down(1), crossterm::event::MouseEventKind::ScrollUp => self.move_up(1), - _ => EventResult::Continue, - } - } - - fn update(&mut self, new_num_items: usize) { - self.num_items = new_num_items; - - if new_num_items <= self.current_index { - self.current_index = new_num_items - 1; - } - - if new_num_items <= self.previous_index { - self.previous_index = new_num_items - 1; + _ => EventResult::NoRedraw, } } diff --git a/src/app/widgets/base/text_input.rs b/src/app/widgets/base/text_input.rs index 2f9e648e..432c04b9 100644 --- a/src/app/widgets/base/text_input.rs +++ b/src/app/widgets/base/text_input.rs @@ -1 +1,138 @@ -pub struct TextInput {} +use crossterm::event::{KeyCode, KeyEvent, KeyModifiers, MouseEvent}; +use tui::layout::Rect; + +use crate::app::{ + event::EventResult::{self}, + Component, +}; + +#[derive(Default)] +/// A single-line component for taking text inputs. +pub struct TextInput { + text: String, + cursor_index: usize, + bounds: Rect, +} + +impl TextInput { + /// Creates a new [`TextInput`]. + pub fn new() -> Self { + Self { + ..Default::default() + } + } + + fn set_cursor(&mut self, new_cursor_index: usize) -> EventResult { + if self.cursor_index == new_cursor_index { + EventResult::NoRedraw + } else { + self.cursor_index = new_cursor_index; + EventResult::Redraw + } + } + + fn move_back(&mut self, amount_to_subtract: usize) -> EventResult { + self.set_cursor(self.cursor_index.saturating_sub(amount_to_subtract)) + } + + fn move_forward(&mut self, amount_to_add: usize) -> EventResult { + let new_cursor = self.cursor_index + amount_to_add; + if new_cursor >= self.text.len() { + self.set_cursor(self.text.len() - 1) + } else { + self.set_cursor(new_cursor) + } + } + + fn clear_text(&mut self) -> EventResult { + if self.text.is_empty() { + EventResult::NoRedraw + } else { + self.text = String::default(); + self.cursor_index = 0; + EventResult::Redraw + } + } + + fn move_word_forward(&mut self) -> EventResult { + // TODO: Implement this + EventResult::NoRedraw + } + + fn move_word_back(&mut self) -> EventResult { + // TODO: Implement this + EventResult::NoRedraw + } + + fn clear_previous_word(&mut self) -> EventResult { + // TODO: Implement this + EventResult::NoRedraw + } + + fn clear_previous_grapheme(&mut self) -> EventResult { + // TODO: Implement this + EventResult::NoRedraw + } + + pub fn update(&mut self, new_text: String) { + self.text = new_text; + + if self.cursor_index >= self.text.len() { + self.cursor_index = self.text.len() - 1; + } + } +} + +impl Component for TextInput { + fn bounds(&self) -> Rect { + self.bounds + } + + fn set_bounds(&mut self, new_bounds: Rect) { + self.bounds = new_bounds; + } + + fn handle_key_event(&mut self, event: KeyEvent) -> EventResult { + if event.modifiers.is_empty() { + match event.code { + KeyCode::Left => self.move_back(1), + KeyCode::Right => self.move_forward(1), + KeyCode::Backspace => self.clear_previous_grapheme(), + _ => EventResult::NoRedraw, + } + } else if let KeyModifiers::CONTROL = event.modifiers { + match event.code { + KeyCode::Char('a') => self.set_cursor(0), + KeyCode::Char('e') => self.set_cursor(self.text.len()), + KeyCode::Char('u') => self.clear_text(), + KeyCode::Char('w') => self.clear_previous_word(), + KeyCode::Char('h') => self.clear_previous_grapheme(), + _ => EventResult::NoRedraw, + } + } else if let KeyModifiers::ALT = event.modifiers { + match event.code { + KeyCode::Char('b') => self.move_word_forward(), + KeyCode::Char('f') => self.move_word_back(), + _ => EventResult::NoRedraw, + } + } else { + EventResult::NoRedraw + } + } + + fn handle_mouse_event(&mut self, event: MouseEvent) -> EventResult { + // We are assuming this is within bounds... + + let x = event.column; + let widget_x = self.bounds.x; + let new_cursor_index = usize::from(x.saturating_sub(widget_x)); + + if new_cursor_index >= self.text.len() { + self.cursor_index = self.text.len() - 1; + } else { + self.cursor_index = new_cursor_index; + } + + EventResult::Redraw + } +} diff --git a/src/app/widgets/base/text_table.rs b/src/app/widgets/base/text_table.rs index 3e113568..6d6088bc 100644 --- a/src/app/widgets/base/text_table.rs +++ b/src/app/widgets/base/text_table.rs @@ -1,24 +1,32 @@ use crossterm::event::{KeyEvent, MouseEvent}; use tui::layout::Rect; -use crate::app::{event::EventResult, Scrollable, Widget}; +use crate::app::{event::EventResult, Component, Scrollable}; -struct Column { - name: &'static str, +/// A [`Column`] represents some column in a [`TextTable`]. +pub struct Column { + pub name: &'static str, + pub shortcut: Option<KeyEvent>, + pub default_descending: bool, // TODO: I would remove these in the future, storing them here feels weird... - desired_column_width: u16, - calculated_column_width: u16, - - x_bounds: (u16, u16), + pub desired_column_width: u16, + pub calculated_column_width: u16, + pub x_bounds: (u16, u16), } -impl Column {} - -/// The [`Widget::UpdateState`] of a [`TextTable`]. -pub struct TextTableUpdateData { - num_items: Option<usize>, - columns: Option<Vec<Column>>, +impl Column { + /// Creates a new [`Column`], given a name and optional shortcut. + pub fn new(name: &'static str, shortcut: Option<KeyEvent>, default_descending: bool) -> Self { + Self { + name, + desired_column_width: 0, + calculated_column_width: 0, + x_bounds: (0, 0), + shortcut, + default_descending, + } + } } /// A sortable, scrollable table with columns. @@ -37,24 +45,30 @@ pub struct TextTable { /// Which index we're sorting by. sort_index: usize, + + /// Whether we're sorting by ascending order. + sort_ascending: bool, } impl TextTable { - pub fn new(num_items: usize, columns: Vec<&'static str>) -> Self { + pub fn new(num_items: usize, columns: Vec<(&'static str, Option<KeyEvent>, bool)>) -> Self { Self { scrollable: Scrollable::new(num_items), columns: columns .into_iter() - .map(|name| Column { + .map(|(name, shortcut, default_descending)| Column { name, desired_column_width: 0, calculated_column_width: 0, x_bounds: (0, 0), + shortcut, + default_descending, }) .collect(), show_gap: true, bounds: Rect::default(), sort_index: 0, + sort_ascending: true, } } @@ -89,12 +103,42 @@ impl TextTable { pub fn column_names(&self) -> Vec<&'static str> { self.columns.iter().map(|column| column.name).collect() } -} -impl Widget for TextTable { - type UpdateData = TextTableUpdateData; + pub fn update_num_items(&mut self, num_items: usize) { + self.scrollable.update_num_items(num_items); + } + + pub fn update_a_column(&mut self, index: usize, column: Column) { + if let Some(c) = self.columns.get_mut(index) { + *c = column; + } + } + pub fn update_columns(&mut self, columns: Vec<Column>) { + self.columns = columns; + if self.columns.len() <= self.sort_index { + self.sort_index = self.columns.len() - 1; + } + } +} + +impl Component for TextTable { fn handle_key_event(&mut self, event: KeyEvent) -> EventResult { + for (index, column) in self.columns.iter().enumerate() { + if let Some(shortcut) = column.shortcut { + if shortcut == event { + if self.sort_index == index { + // Just flip the sort if we're already sorting by this. + self.sort_ascending = !self.sort_ascending; + } else { + self.sort_index = index; + self.sort_ascending = !column.default_descending; + } + return EventResult::Redraw; + } + } + } + self.scrollable.handle_key_event(event) } @@ -107,29 +151,22 @@ impl Widget for TextTable { for (index, column) in self.columns.iter().enumerate() { let (start, end) = column.x_bounds; if start >= x && end <= y { - self.sort_index = index; + if self.sort_index == index { + // Just flip the sort if we're already sorting by this. + self.sort_ascending = !self.sort_ascending; + } else { + self.sort_index = index; + self.sort_ascending = !column.default_descending; + } } } - EventResult::Continue + EventResult::NoRedraw } else { self.scrollable.handle_mouse_event(event) } } - fn update(&mut self, update_data: Self::UpdateData) { - if let Some(num_items) = update_data.num_items { - self.scrollable.update(num_items); - } - - if let Some(columns) = update_data.columns { - self.columns = columns; - if self.columns.len() <= self.sort_index { - self.sort_index = self.columns.len() - 1; - } - } - } - fn bounds(&self) -> Rect { self.bounds } diff --git a/src/app/widgets/base/time_graph.rs b/src/app/widgets/base/time_graph.rs index 26adfcb4..3c19bb0a 100644 --- a/src/app/widgets/base/time_graph.rs +++ b/src/app/widgets/base/time_graph.rs @@ -3,7 +3,7 @@ use std::time::{Duration, Instant}; use crossterm::event::{KeyEvent, KeyModifiers, MouseEvent}; use tui::layout::Rect; -use crate::app::{event::EventResult, Widget}; +use crate::app::{event::EventResult, Component}; #[derive(Clone)] pub enum AutohideTimerState { @@ -23,7 +23,9 @@ pub enum AutohideTimer { impl AutohideTimer { fn trigger_display_timer(&mut self) { match self { - AutohideTimer::Disabled => todo!(), + AutohideTimer::Disabled => { + // Does nothing. + } AutohideTimer::Enabled { state, show_duration: _, @@ -35,7 +37,9 @@ impl AutohideTimer { pub fn update_display_timer(&mut self) { match self { - AutohideTimer::Disabled => {} + AutohideTimer::Disabled => { + // Does nothing. + } AutohideTimer::Enabled { state, show_duration, @@ -87,7 +91,7 @@ impl TimeGraph { '-' => self.zoom_out(), '+' => self.zoom_in(), '=' => self.reset_zoom(), - _ => EventResult::Continue, + _ => EventResult::NoRedraw, } } @@ -105,7 +109,7 @@ impl TimeGraph { EventResult::Redraw } else { - EventResult::Continue + EventResult::NoRedraw } } @@ -123,13 +127,13 @@ impl TimeGraph { EventResult::Redraw } else { - EventResult::Continue + EventResult::NoRedraw } } fn reset_zoom(&mut self) -> EventResult { if self.current_display_time == self.default_time_value { - EventResult::Continue + EventResult::NoRedraw } else { self.current_display_time = self.default_time_value; self.autohide_timer.trigger_display_timer(); @@ -138,19 +142,17 @@ impl TimeGraph { } } -impl Widget for TimeGraph { - type UpdateData = (); - +impl Component for TimeGraph { fn handle_key_event(&mut self, event: KeyEvent) -> EventResult { use crossterm::event::KeyCode::Char; if event.modifiers == KeyModifiers::NONE || event.modifiers == KeyModifiers::SHIFT { match event.code { Char(c) => self.handle_char(c), - _ => EventResult::Continue, + _ => EventResult::NoRedraw, } } else { - EventResult::Continue + EventResult::NoRedraw } } @@ -158,7 +160,7 @@ impl Widget for TimeGraph { match event.kind { crossterm::event::MouseEventKind::ScrollDown => self.zoom_out(), crossterm::event::MouseEventKind::ScrollUp => self.zoom_in(), - _ => EventResult::Continue, + _ => EventResult::NoRedraw, } } diff --git a/src/app/widgets/basic_cpu.rs b/src/app/widgets/basic_cpu.rs new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/src/app/widgets/basic_cpu.rs diff --git a/src/app/widgets/basic_mem.rs b/src/app/widgets/basic_mem.rs new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/src/app/widgets/basic_mem.rs diff --git a/src/app/widgets/basic_net.rs b/src/app/widgets/basic_net.rs new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/src/app/widgets/basic_net.rs diff --git a/src/app/widgets/battery.rs b/src/app/widgets/battery.rs index 62f27d93..64236163 100644 --- a/src/app/widgets/battery.rs +++ b/src/app/widgets/battery.rs @@ -1,5 +1,9 @@ use std::collections::HashMap; +use tui::layout::Rect; + +use super::{Component, Widget}; + #[derive(Default)] pub struct BatteryWidgetState { pub currently_selected_battery_index: usize, @@ -23,3 +27,30 @@ impl BatteryState { self.widget_states.get(&widget_id) } } + +// TODO: Implement battery widget. +/// A table displaying battery information on a per-battery basis. +pub struct BatteryTable { + bounds: Rect, +} + +impl BatteryTable { + /// Creates a new [`BatteryTable`]. + pub fn new() -> Self { + Self { + bounds: Rect::default(), + } + } +} + +impl Component for BatteryTable { + fn bounds(&self) -> tui::layout::Rect { + self.bounds + } + + fn set_bounds(&mut self, new_bounds: tui::layout::Rect) { + self.bounds = new_bounds; + } +} + +impl Widget for BatteryTable {} diff --git a/src/app/widgets/cpu.rs b/src/app/widgets/cpu.rs index 48c97dbc..ceb5e0d5 100644 --- a/src/app/widgets/cpu.rs +++ b/src/app/widgets/cpu.rs @@ -6,8 +6,8 @@ use tui::layout::Rect; use crate::app::event::EventResult; use super::{ - does_point_intersect_rect, text_table::TextTableUpdateData, AppScrollWidgetState, - CanvasTableWidthState, TextTable, TimeGraph, Widget, + does_point_intersect_rect, AppScrollWidgetState, CanvasTableWidthState, Component, TextTable, + TimeGraph, Widget, }; pub struct CpuWidgetState { @@ -66,10 +66,6 @@ pub enum CpuGraphLegendPosition { Right, } -pub struct CpuGraphUpdateData { - pub legend_data: Option<TextTableUpdateData>, -} - /// A widget designed to show CPU usage via a graph, along with a side legend implemented as a [`TextTable`]. pub struct CpuGraph { graph: TimeGraph, @@ -95,21 +91,16 @@ impl CpuGraph { } } -impl Widget for CpuGraph { - type UpdateData = CpuGraphUpdateData; - +impl Component for CpuGraph { fn handle_key_event(&mut self, event: KeyEvent) -> EventResult { match self.selected { CpuGraphSelection::Graph => self.graph.handle_key_event(event), CpuGraphSelection::Legend => self.legend.handle_key_event(event), - CpuGraphSelection::None => EventResult::Continue, + CpuGraphSelection::None => EventResult::NoRedraw, } } fn handle_mouse_event(&mut self, event: MouseEvent) -> EventResult { - // Check where we clicked (and switch the selected field if required) and fire the handler from there. - // Note we assume that the - let global_x = event.column; let global_y = event.row; @@ -120,13 +111,7 @@ impl Widget for CpuGraph { self.selected = CpuGraphSelection::Legend; self.legend.handle_mouse_event(event) } else { - EventResult::Continue - } - } - - fn update(&mut self, update_data: Self::UpdateData) { - if let Some(legend_data) = update_data.legend_data { - self.legend.update(legend_data); + EventResult::NoRedraw } } @@ -138,3 +123,5 @@ impl Widget for CpuGraph { self.bounds = new_bounds; } } + +impl Widget for CpuGraph {} diff --git a/src/app/widgets/disk.rs b/src/app/widgets/disk.rs index 9142dac0..7ae70229 100644 --- a/src/app/widgets/disk.rs +++ b/src/app/widgets/disk.rs @@ -5,10 +5,7 @@ use tui::layout::Rect; use crate::app::event::EventResult; -use super::{ - text_table::TextTableUpdateData, AppScrollWidgetState, CanvasTableWidthState, TextTable, - Widget, -}; +use super::{AppScrollWidgetState, CanvasTableWidthState, Component, TextTable, Widget}; pub struct DiskWidgetState { pub scroll_state: AppScrollWidgetState, @@ -58,9 +55,7 @@ impl DiskTable { } } -impl Widget for DiskTable { - type UpdateData = TextTableUpdateData; - +impl Component for DiskTable { fn handle_key_event(&mut self, event: KeyEvent) -> EventResult { self.table.handle_key_event(event) } @@ -69,10 +64,6 @@ impl Widget for DiskTable { self.table.handle_mouse_event(event) } - fn update(&mut self, update_data: Self::UpdateData) { - self.table.update(update_data); - } - fn bounds(&self) -> Rect { self.bounds } @@ -81,3 +72,5 @@ impl Widget for DiskTable { self.bounds = new_bounds; } } + +impl Widget for DiskTable {} diff --git a/src/app/widgets/mem.rs b/src/app/widgets/mem.rs index 9409b94c..a11d48a0 100644 --- a/src/app/widgets/mem.rs +++ b/src/app/widgets/mem.rs @@ -5,7 +5,7 @@ use tui::layout::Rect; use crate::app::event::EventResult; -use super::{TimeGraph, Widget}; +use super::{Component, TimeGraph, Widget}; pub struct MemWidgetState { pub current_display_time: u64, @@ -56,9 +56,7 @@ impl MemGraph { } } -impl Widget for MemGraph { - type UpdateData = (); - +impl Component for MemGraph { fn handle_key_event(&mut self, event: KeyEvent) -> EventResult { self.graph.handle_key_event(event) } @@ -75,3 +73,5 @@ impl Widget for MemGraph { self.graph.set_bounds(new_bounds); } } + +impl Widget for MemGraph {} diff --git a/src/app/widgets/mod.rs b/src/app/widgets/mod.rs index e7f63b45..a80aa5dc 100644 --- a/src/app/widgets/mod.rs +++ b/src/app/widgets/mod.rs @@ -2,10 +2,14 @@ use std::time::Instant; use crossterm::event::{KeyEvent, MouseEvent}; use enum_dispatch::enum_dispatch; +use indextree::{Arena, NodeId}; use tui::{layout::Rect, widgets::TableState}; use crate::{ - app::{event::EventResult, layout_manager::BottomWidgetType}, + app::{ + event::{EventResult, SelectionAction}, + layout_manager::BottomWidgetType, + }, constants, }; @@ -33,37 +37,65 @@ pub use self::battery::*; pub mod temp; pub use temp::*; +/// A trait for things that are drawn with state. #[enum_dispatch] #[allow(unused_variables)] -pub trait Widget { - type UpdateData; - +pub trait Component { /// Handles a [`KeyEvent`]. /// - /// Defaults to returning [`EventResult::Continue`], indicating nothing should be done. + /// Defaults to returning [`EventResult::NoRedraw`], indicating nothing should be done. fn handle_key_event(&mut self, event: KeyEvent) -> EventResult { - EventResult::Continue + EventResult::NoRedraw } /// Handles a [`MouseEvent |