summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md20
-rw-r--r--README.md21
-rw-r--r--src/app.rs103
-rw-r--r--src/canvas.rs132
-rw-r--r--src/canvas/dialogs/filter_dialog.rs0
-rw-r--r--src/canvas/dialogs/help_dialog.rs144
-rw-r--r--src/canvas/drawing_utils.rs9
-rw-r--r--src/canvas/widgets/cpu_graph.rs2
-rw-r--r--src/canvas/widgets/disk_table.rs2
-rw-r--r--src/canvas/widgets/process_table.rs4
-rw-r--r--src/canvas/widgets/temp_table.rs2
-rw-r--r--src/constants.rs88
-rw-r--r--src/main.rs22
13 files changed, 375 insertions, 174 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2b2a0ef2..80f59a6c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -27,12 +27,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- `"processes"`
- `"temperature"`
-- Removed an (undocumented) feature in allowing modifying total RX/TX colours. This is mainly due to the legend change.
-
-- Updated error messages to be a bit more consistent/helpful.
-
- [#117](https://github.com/ClementTsang/bottom/issues/117): Update tui to 0.9:
+ - Removed an (undocumented) feature in allowing modifying total RX/TX colours. This is mainly due to the legend change.
+
- Use custom legend-hiding to stop hiding legends for memory and network widgets.
- In addition, changed to using only legends within the graph for network, as well as redesigned the legend.
@@ -40,9 +38,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Allow for option to hide the header gap on tables via `--hide_table_gap` or `hide_table_gap = true`.
- - Switch to stateful widget style for tables.
+- [#126](https://github.com/ClementTsang/bottom/pull/126): Updated error messages to be a bit more consistent/helpful.
- - Switch to using tui-rs' new built in linear interpolation rather than doing it manually.
+- Redesigned help menu to allow for scrolling.
### Bug Fixes
@@ -51,9 +49,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Fixed bug where a single empty row as a layout would crash without a proper warning.
The behaviour now errors out with a more helpful message.
-### Other
+### Development changes
+
+- Switch to stateful widget style for tables.
+
+- Switch to using tui-rs' new built in linear interpolation rather than doing it manually.
+
+- Updated arg tests and added config testing.
-- Updated tests and added config testing.
+- More refactoring.
## [0.3.0] - 2020-04-07
diff --git a/README.md b/README.md
index 8767a79e..a5e23fe1 100644
--- a/README.md
+++ b/README.md
@@ -7,6 +7,8 @@
A cross-platform graphical process/system monitor with a customizable interface and a multitude of features. Supports Linux, macOS, and Windows. Inspired by both [gtop](https://github.com/aksakalli/gtop) and [gotop](https://github.com/cjbassi/gotop).
+<!--TODO: Update recording for 0.4-->
+
![Quick demo recording showing off searching, maximizing, and process killing.](assets/summary_and_search.gif) _Theme based on [gruvbox](https://github.com/morhetz/gruvbox) (see [sample config](./sample_configs/demo_config.toml))._ Recorded on version 0.2.0.
**Note**: This documentation is relevant to version 0.4.0 and may refer to in-development features, especially if you are reading this on the master branch. Please refer to [release branch](https://github.com/ClementTsang/bottom/tree/release/README.md) or [crates.io](https://crates.io/crates/bottom) for the most up-to-date _release_ documentation.
@@ -163,19 +165,19 @@ Run using `btm`.
| | |
| -------------------------------------------------- | ---------------------------------------------------------------------------------------------- |
-| `q`, `Ctrl-c` | Quit bottom |
+| `q`, `Ctrl-c` | Quit |
| `Esc` | Close dialog windows, search, widgets, or exit maximized mode |
| `Ctrl-r` | Reset display and any collected data |
| `f` | Freeze/unfreeze updating with new data |
| `Ctrl`-arrow key<br>`Shift`-arrow key<br>`H/J/K/L` | Move to a different widget (on macOS some keybindings may conflict) |
-| `Up`,`k` | Scroll up in tables |
-| `Down`, `j` | Scroll down in tables |
+| `Up`,`k` | Scroll up |
+| `Down`, `j` | Scroll down |
| `?` | Open help menu |
-| `gg`, `Home` | Jump to the first entry of a table |
-| `Shift-g`, `End` | Jump to the last entry of a table |
-| `Enter` | Maximize widget |
-| `+` | Zoom in on a chart |
-| `-` | Zoom out on a chart |
+| `gg`, `Home` | Jump to the first entry |
+| `Shift-g`, `End` | Jump to the last entry |
+| `Enter` | Maximize the currently selected widget |
+| `+` | Zoom in on chart (decrease time range) |
+| `-` | Zoom out on chart (increase time range) |
| `=` | Reset zoom |
| Mouse scroll | Table: Scrolls through the list<br>Chart: Zooms in or out by scrolling up or down respectively |
@@ -207,6 +209,9 @@ Run using `btm`.
| `Esc` | Close the search widget (retains the filter) |
| `Ctrl-a` | Skip to the start of the search query |
| `Ctrl-e` | Skip to the end of the search query |
+| `Ctrl-u` | Clear the current search query |
+| `Backspace` | Delete the character behind the cursor |
+| `Delete` | Delete the character at the cursor |
| `Alt-c`/`F1` | Toggle matching case |
| `Alt-w`/`F2` | Toggle matching the entire word |
| `Alt-r`/`F3` | Toggle using regex |
diff --git a/src/app.rs b/src/app.rs
index 4f32b398..a71c4192 100644
--- a/src/app.rs
+++ b/src/app.rs
@@ -64,18 +64,15 @@ pub enum AppHelpCategory {
Search,
}
+#[derive(Default)]
pub struct AppHelpDialogState {
pub is_showing_help: bool,
- pub current_category: AppHelpCategory,
-}
-
-impl Default for AppHelpDialogState {
- fn default() -> Self {
- AppHelpDialogState {
- is_showing_help: false,
- current_category: AppHelpCategory::General,
- }
- }
+ pub scroll_state: ParagraphScrollState,
+ pub general_index: u16,
+ pub cpu_index: u16,
+ pub process_index: u16,
+ pub search_index: u16,
+ pub battery_index: u16,
}
/// AppConfigFields is meant to cover basic fields that would normally be set
@@ -481,6 +478,12 @@ impl BatteryState {
}
}
+#[derive(Default)]
+pub struct ParagraphScrollState {
+ pub current_scroll_index: u16,
+ pub max_scroll_index: u16,
+}
+
#[derive(TypedBuilder)]
pub struct App {
#[builder(default = false, setter(skip))]
@@ -517,7 +520,7 @@ pub struct App {
pub is_expanded: bool,
#[builder(default = false, setter(skip))]
- pub is_resized: bool,
+ pub is_force_redraw: bool,
pub cpu_state: CpuState,
pub mem_state: MemState,
@@ -581,11 +584,11 @@ impl App {
self.reset_multi_tap_keys();
if self.is_in_dialog() {
self.help_dialog_state.is_showing_help = false;
- self.help_dialog_state.current_category = AppHelpCategory::General;
self.delete_dialog_state.is_showing_dd = false;
self.delete_dialog_state.is_on_yes = false;
self.to_delete_process_list = None;
self.dd_err = None;
+ self.is_force_redraw = true;
} else if self.is_filtering_or_searching() {
match self.current_widget.widget_type {
BottomWidgetType::Cpu => {
@@ -603,7 +606,7 @@ impl App {
cpu_widget_state.scroll_state.current_scroll_position = new_position;
cpu_widget_state.scroll_state.previous_scroll_position = 0;
}
- self.is_resized = true;
+ self.is_force_redraw = true;
}
}
BottomWidgetType::CpuLegend => {
@@ -621,7 +624,7 @@ impl App {
cpu_widget_state.scroll_state.current_scroll_position = new_position;
cpu_widget_state.scroll_state.previous_scroll_position = 0;
}
- self.is_resized = true;
+ self.is_force_redraw = true;
}
}
BottomWidgetType::Proc => {
@@ -636,7 +639,7 @@ impl App {
.search_state
.is_enabled = false;
}
- self.is_resized = true;
+ self.is_force_redraw = true;
}
}
BottomWidgetType::ProcSearch => {
@@ -652,14 +655,14 @@ impl App {
.is_enabled = false;
self.move_widget_selection_up();
}
- self.is_resized = true;
+ self.is_force_redraw = true;
}
}
_ => {}
}
} else if self.is_expanded {
self.is_expanded = false;
- self.is_resized = true;
+ self.is_force_redraw = true;
}
}
@@ -974,7 +977,7 @@ impl App {
BottomWidgetType::ProcSearch => {}
_ => {
self.is_expanded = true;
- self.is_resized = true;
+ self.is_force_redraw = true;
}
}
}
@@ -1098,13 +1101,19 @@ impl App {
pub fn on_up_key(&mut self) {
if !self.is_in_dialog() {
self.decrement_position_count();
+ } else if self.help_dialog_state.is_showing_help {
+ self.help_scroll_up();
}
+ self.reset_multi_tap_keys();
}
pub fn on_down_key(&mut self) {
if !self.is_in_dialog() {
self.increment_position_count();
+ } else if self.help_dialog_state.is_showing_help {
+ self.help_scroll_down();
}
+ self.reset_multi_tap_keys();
}
pub fn on_left_key(&mut self) {
@@ -1428,10 +1437,16 @@ impl App {
}
self.handle_char(caught_char);
} else if self.help_dialog_state.is_showing_help {
+ // TODO: Seems weird that we have it like this; it would be better to make this
+ // more obvious that we are separating dialog logic and normal logic IMO.
+ // This is even more so as most logic already checks for dialog state.
match caught_char {
- '1' => self.help_dialog_state.current_category = AppHelpCategory::General,
- '2' => self.help_dialog_state.current_category = AppHelpCategory::Process,
- '3' => self.help_dialog_state.current_category = AppHelpCategory::Search,
+ '1' => self.help_scroll_to_or_max(self.help_dialog_state.general_index),
+ '2' => self.help_scroll_to_or_max(self.help_dialog_state.cpu_index),
+ '3' => self.help_scroll_to_or_max(self.help_dialog_state.process_index),
+ '4' => self.help_scroll_to_or_max(self.help_dialog_state.search_index),
+ '5' => self.help_scroll_to_or_max(self.help_dialog_state.battery_index),
+ 'j' | 'k' | 'g' | 'G' => self.handle_char(caught_char),
_ => {}
}
}
@@ -1478,8 +1493,8 @@ impl App {
}
}
'G' => self.skip_to_last(),
- 'k' => self.decrement_position_count(),
- 'j' => self.increment_position_count(),
+ 'k' => self.on_up_key(),
+ 'j' => self.on_down_key(),
'f' => {
self.is_frozen = !self.is_frozen;
if self.is_frozen {
@@ -1584,6 +1599,7 @@ impl App {
}
'?' => {
self.help_dialog_state.is_showing_help = true;
+ self.is_force_redraw = true;
}
'H' => self.move_widget_selection_left(),
'L' => self.move_widget_selection_right(),
@@ -2019,6 +2035,8 @@ impl App {
_ => {}
}
self.reset_multi_tap_keys();
+ } else {
+ self.help_dialog_state.scroll_state.current_scroll_index = 0;
}
}
@@ -2093,6 +2111,12 @@ impl App {
_ => {}
}
self.reset_multi_tap_keys();
+ } else {
+ self.help_dialog_state.scroll_state.current_scroll_index = self
+ .help_dialog_state
+ .scroll_state
+ .max_scroll_index
+ .saturating_sub(1);
}
}
@@ -2105,7 +2129,6 @@ impl App {
BottomWidgetType::CpuLegend => self.change_cpu_table_position(-1),
_ => {}
}
- self.reset_multi_tap_keys();
}
}
@@ -2118,7 +2141,6 @@ impl App {
BottomWidgetType::CpuLegend => self.change_cpu_table_position(1),
_ => {}
}
- self.reset_multi_tap_keys();
}
}
@@ -2228,8 +2250,33 @@ impl App {
}
}
+ fn help_scroll_up(&mut self) {
+ if self.help_dialog_state.scroll_state.current_scroll_index > 0 {
+ self.help_dialog_state.scroll_state.current_scroll_index -= 1;
+ }
+ }
+
+ fn help_scroll_down(&mut self) {
+ if self.help_dialog_state.scroll_state.current_scroll_index + 1
+ < self.help_dialog_state.scroll_state.max_scroll_index
+ {
+ self.help_dialog_state.scroll_state.current_scroll_index += 1;
+ }
+ }
+
+ fn help_scroll_to_or_max(&mut self, new_position: u16) {
+ if new_position < self.help_dialog_state.scroll_state.max_scroll_index {
+ self.help_dialog_state.scroll_state.current_scroll_index = new_position;
+ } else {
+ self.help_dialog_state.scroll_state.current_scroll_index =
+ self.help_dialog_state.scroll_state.max_scroll_index - 1;
+ }
+ }
+
pub fn handle_scroll_up(&mut self) {
- if self.current_widget.widget_type.is_widget_graph() {
+ if self.help_dialog_state.is_showing_help {
+ self.help_scroll_up();
+ } else if self.current_widget.widget_type.is_widget_graph() {
self.zoom_in();
} else if self.current_widget.widget_type.is_widget_table() {
self.decrement_position_count();
@@ -2237,7 +2284,9 @@ impl App {
}
pub fn handle_scroll_down(&mut self) {
- if self.current_widget.widget_type.is_widget_graph() {
+ if self.help_dialog_state.is_showing_help {
+ self.help_scroll_down();
+ } else if self.current_widget.widget_type.is_widget_graph() {
self.zoom_out();
} else if self.current_widget.widget_type.is_widget_table() {
self.increment_position_count();
diff --git a/src/canvas.rs b/src/canvas.rs
index 9e4aaf30..ad332655 100644
--- a/src/canvas.rs
+++ b/src/canvas.rs
@@ -59,9 +59,7 @@ pub struct Painter {
pub colours: CanvasColours,
height: u16,
width: u16,
- styled_general_help_text: Vec<Text<'static>>,
- styled_process_help_text: Vec<Text<'static>>,
- styled_search_help_text: Vec<Text<'static>>,
+ styled_help_text: Vec<Text<'static>>,
is_mac_os: bool,
row_constraints: Vec<Constraint>,
col_constraints: Vec<Vec<Constraint>>,
@@ -145,9 +143,7 @@ impl Painter {
colours: CanvasColours::default(),
height: 0,
width: 0,
- styled_general_help_text: Vec::new(),
- styled_process_help_text: Vec::new(),
- styled_search_help_text: Vec::new(),
+ styled_help_text: Vec::new(),
is_mac_os: false,
row_constraints,
col_constraints,
@@ -164,44 +160,79 @@ impl Painter {
pub fn complete_painter_init(&mut self) {
self.is_mac_os = cfg!(target_os = "macos");
- if GENERAL_HELP_TEXT.len() > 1 {
- self.styled_general_help_text.push(Text::Styled(
- GENERAL_HELP_TEXT[0].into(),
- self.colours.table_header_style,
- ));
- self.styled_general_help_text.extend(
- GENERAL_HELP_TEXT[1..]
- .iter()
- .map(|&text| Text::Styled(text.into(), self.colours.text_style))
- .collect::<Vec<_>>(),
- );
- }
-
- if PROCESS_HELP_TEXT.len() > 1 {
- self.styled_process_help_text.push(Text::Styled(
- PROCESS_HELP_TEXT[0].into(),
- self.colours.table_header_style,
- ));
- self.styled_process_help_text.extend(
- PROCESS_HELP_TEXT[1..]
- .iter()
- .map(|&text| Text::Styled(text.into(), self.colours.text_style))
- .collect::<Vec<_>>(),
- );
- }
-
- if SEARCH_HELP_TEXT.len() > 1 {
- self.styled_search_help_text.push(Text::Styled(
- SEARCH_HELP_TEXT[0].into(),
- self.colours.table_header_style,
- ));
- self.styled_search_help_text.extend(
- SEARCH_HELP_TEXT[1..]
- .iter()
- .map(|&text| Text::Styled(text.into(), self.colours.text_style))
- .collect::<Vec<_>>(),
- );
- }
+ // Init help text:
+ // ToC
+ self.styled_help_text.extend(
+ HELP_CONTENTS_TEXT
+ .iter()
+ .map(|&text| Text::Styled(text.into(), self.colours.text_style))
+ .collect::<Vec<_>>(),
+ );
+
+ // General
+ self.styled_help_text.push(Text::Raw("\n\n".into()));
+ self.styled_help_text.push(Text::Styled(
+ GENERAL_HELP_TEXT[0].into(),
+ self.colours.table_header_style,
+ ));
+ self.styled_help_text.extend(
+ GENERAL_HELP_TEXT[1..]
+ .iter()
+ .map(|&text| Text::Styled(text.into(), self.colours.text_style))
+ .collect::<Vec<_>>(),
+ );
+
+ // CPU
+ self.styled_help_text.push(Text::Raw("\n\n".into()));
+ self.styled_help_text.push(Text::Styled(
+ CPU_HELP_TEXT[0].into(),
+ self.colours.table_header_style,
+ ));
+ self.styled_help_text.extend(
+ CPU_HELP_TEXT[1..]
+ .iter()
+ .map(|&text| Text::Styled(text.into(), self.colours.text_style))
+ .collect::<Vec<_>>(),
+ );
+
+ // Proc
+ self.styled_help_text.push(Text::Raw("\n\n".into()));
+ self.styled_help_text.push(Text::Styled(
+ PROCESS_HELP_TEXT[0].into(),
+ self.colours.table_header_style,
+ ));
+ self.styled_help_text.extend(
+ PROCESS_HELP_TEXT[1..]
+ .iter()
+ .map(|&text| Text::Styled(text.into(), self.colours.text_style))
+ .collect::<Vec<_>>(),
+ );
+
+ // Proc Search
+ self.styled_help_text.push(Text::Raw("\n\n".into()));
+ self.styled_help_text.push(Text::Styled(
+ SEARCH_HELP_TEXT[0].into(),
+ self.colours.table_header_style,
+ ));
+ self.styled_help_text.extend(
+ SEARCH_HELP_TEXT[1..]
+ .iter()
+ .map(|&text| Text::Styled(text.into(), self.colours.text_style))
+ .collect::<Vec<_>>(),
+ );
+
+ // Battery
+ self.styled_help_text.push(Text::Raw("\n\n".into()));
+ self.styled_help_text.push(Text::Styled(
+ BATTERY_HELP_TEXT[0].into(),
+ self.colours.table_header_style,
+ ));
+ self.styled_help_text.extend(
+ BATTERY_HELP_TEXT[1..]
+ .iter()
+ .map(|&text| Text::Styled(text.into(), self.colours.text_style))
+ .collect::<Vec<_>>(),
+ );
}
// TODO: [FEATURE] Auto-resizing dialog sizes.
@@ -214,11 +245,10 @@ impl Painter {
let current_height = terminal_size.height;
let current_width = terminal_size.width;
- if self.height == 0 && self.width == 0 {
- self.height = current_height;
- self.width = current_width;
- } else if self.height != current_height || self.width != current_width {
- app_state.is_resized = true;
+ if (self.height == 0 && self.width == 0)
+ || (self.height != current_height || self.width != current_width)
+ {
+ app_state.is_force_redraw = true;
self.height = current_height;
self.width = current_width;
}
@@ -434,7 +464,7 @@ impl Painter {
}
} else {
// Draws using the passed in (or default) layout. NOT basic so far.
- if self.derived_widget_draw_locs.is_empty() || app_state.is_resized {
+ if self.derived_widget_draw_locs.is_empty() || app_state.is_force_redraw {
let row_draw_locs = Layout::default()
.margin(0)
.constraints(self.row_constraints.as_ref())
@@ -531,7 +561,7 @@ impl Painter {
}
})?;
- app_state.is_resized = false;
+ app_state.is_force_redraw = false;
Ok(())
}
diff --git a/src/canvas/dialogs/filter_dialog.rs b/src/canvas/dialogs/filter_dialog.rs
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/src/canvas/dialogs/filter_dialog.rs
diff --git a/src/canvas/dialogs/help_dialog.rs b/src/canvas/dialogs/help_dialog.rs
index 8dbca876..70492ae9 100644
--- a/src/canvas/dialogs/help_dialog.rs
+++ b/src/canvas/dialogs/help_dialog.rs
@@ -1,4 +1,5 @@
use std::cmp::max;
+use unicode_width::UnicodeWidthStr;
use tui::{
backend::Backend,
@@ -7,12 +8,9 @@ use tui::{
widgets::{Block, Borders, Paragraph},
};
-use crate::{
- app::{App, AppHelpCategory},
- canvas::Painter,
-};
+use crate::{app::App, canvas::Painter, constants};
-const HELP_BASE: &str = " Help ── 1: General ─── 2: Processes ─── 3: Search ─── Esc to close ";
+const HELP_BASE: &str = " Help ── Esc to close ";
pub trait HelpDialog {
fn draw_help_dialog<B: Backend>(
@@ -28,31 +26,121 @@ impl HelpDialog for Painter {
0,
draw_loc.width as i32 - HELP_BASE.chars().count() as i32 - 2,
);
- let help_title = format!(
- " Help ─{}─ 1: General ─── 2: Processes ─── 3: Search ─── Esc to close ",
- "─".repeat(repeat_num as usize)
- );
+ let help_title = format!(" Help ─{}─ Esc to close ", "─".repeat(repeat_num as usize));
+
+ if app_state.is_force_redraw {
+ // We must also recalculate how many lines are wrapping to properly get scrolling to work on
+ // small terminal sizes... oh joy.
+
+ // TODO: Make this more automated and easier to add.
+
+ let mut overflow_buffer = 0;
+ let paragraph_width = draw_loc.width - 2;
+ constants::HELP_CONTENTS_TEXT.iter().for_each(|text_line| {
+ overflow_buffer +=
+ UnicodeWidthStr::width(*text_line).saturating_sub(1) as u16 / paragraph_width;
+ });
+
+ // General
+ app_state.help_dialog_state.general_index =
+ constants::HELP_CONTENTS_TEXT.len() as u16 + 1 + overflow_buffer;
+ constants::GENERAL_HELP_TEXT.iter().for_each(|text_line| {
+ overflow_buffer +=
+ UnicodeWidthStr::width(*text_line).saturating_sub(1) as u16 / paragraph_width;
+ });
+
+ // CPU
+ app_state.help_dialog_state.cpu_index =
+ (constants::HELP_CONTENTS_TEXT.len() + constants::GENERAL_HELP_TEXT.len()) as u16
+ + 2
+ + overflow_buffer;
+ constants::CPU_HELP_TEXT.iter().for_each(|text_line| {
+ overflow_buffer +=
+ UnicodeWidthStr::width(*text_line).saturating_sub(1) as u16 / paragraph_width;
+ });
+
+ // Processes
+ app_state.help_dialog_state.process_index = (constants::HELP_CONTENTS_TEXT.len()
+ + constants::GENERAL_HELP_TEXT.len()
+ + constants::CPU_HELP_TEXT.len())
+ as u16
+ + 3
+ + overflow_buffer;
+ constants::PROCESS_HELP_TEXT.iter().for_each(|text_line| {
+ overflow_buffer +=
+ UnicodeWidthStr::width(*text_line).saturating_sub(1) as u16 / paragraph_width;
+ });
+
+ // Search
+ app_state.help_dialog_state.search_index = (constants::HELP_CONTENTS_TEXT.len()
+ + constants::GENERAL_HELP_TEXT.len()
+ + constants::CPU_HELP_TEXT.len()
+ + constants::PROCESS_HELP_TEXT.len())
+ as u16
+ + 4
+ + overflow_buffer;
+ constants::SEARCH_HELP_TEXT.iter().for_each(|text_line| {
+ overflow_buffer +=
+ UnicodeWidthStr::width(*text_line).saturating_sub(1) as u16 / paragraph_width;
+ });
+
+ // Battery
+ app_state.help_dialog_state.battery_index = (constants::HELP_CONTENTS_TEXT.len()
+ + constants::GENERAL_HELP_TEXT.len()
+ + constants::CPU_HELP_TEXT.len()
+ + constants::PROCESS_HELP_TEXT.len()
+ + constants::SEARCH_HELP_TEXT.len())
+ as u16
+ + 5
+ + overflow_buffer;
+ constants::BATTERY_HELP_TEXT.iter().for_each(|text_line| {
+ overflow_buffer +=
+ UnicodeWidthStr::width(*text_line).saturating_sub(1) as u16 / paragraph_width;
+ });
+
+ app_state.help_dialog_state.scroll_state.max_scroll_index =
+ (self.styled_help_text.len() as u16
+ + (constants::NUM_CATEGORIES - 3)
+ + overflow_buffer)
+ .saturating_sub(draw_loc.height);
+
+ // Fix if over-scrolled
+ if app_state
+ .help_dialog_state
+ .scroll_state
+ .current_scroll_index
+ >= app_state.help_dialog_state.scroll_state.max_scroll_index
+ {
+ app_state
+ .help_dialog_state
+ .scroll_state
+ .current_scroll_index = app_state
+ .help_dialog_state
+ .scroll_state
+ .max_scroll_index
+ .saturating_sub(1);
+ }
+ }
f.render_widget(
- Paragraph::new(
- match app_state.help_dialog_state.current_category {
- AppHelpCategory::General => &self.styled_general_help_text,
- AppHelpCategory::Process => &self.styled_process_help_text,
- AppHelpCategory::Search => &self.styled_search_help_text,
- }
- .iter(),
- )
- .block(
- Block::default()
- .title(&help_title)
- .title_style(self.colours.border_style)
- .style(self.colours.border_style)
- .borders(Borders::ALL)
- .border_style(self.colours.border_style),
- )
- .style(self.colours.text_style)
- .alignment(Alignment::Left)
- .wrap(true),
+ Paragraph::new(self.styled_help_text.iter())
+ .block(
+ Block::default()
+ .title(&help_title)
+ .title_style(self.colours.border_style)
+ .style(self.colours.border_style)
+ .borders(Borders::ALL)
+ .border_style(self.colours.border_style),
+ )
+ .style(self.colours.text_style)
+ .alignment(Alignment::Left)
+ .wrap(true)
+ .scroll(
+ app_state
+ .help_dialog_state
+ .scroll_state
+ .current_scroll_index,
+ ),
draw_loc,
);
}
diff --git a/src/canvas/drawing_utils.rs b/src/canvas/drawing_utils.rs
index 6c008724..2281e503 100644
--- a/src/canvas/drawing_utils.rs
+++ b/src/canvas/drawing_utils.rs
@@ -1,6 +1,7 @@
use crate::app;
use itertools::izip;
+// TODO: Reverse intrinsic?
/// A somewhat jury-rigged solution to simulate a variable intrinsic layout for
/// table widths. Note that this will do one main pass to try to properly
/// allocate widths. This will thus potentially cut off latter elements
@@ -77,9 +78,9 @@ pub fn get_variable_intrinsic_widths(
pub fn get_search_start_position(
num_columns: usize, cursor_direction: &app::CursorDirection, cursor_bar: &mut usize,
- current_cursor_position: usize, is_resized: bool,
+ current_cursor_position: usize, is_force_redraw: bool,
) -> usize {
- if is_resized {
+ if is_force_redraw {
*cursor_bar = 0;
}
@@ -117,9 +118,9 @@ pub fn get_search_start_position(
pub fn get_start_position(
num_rows: u64, scroll_direction: &app::ScrollDirection, scroll_position_bar: &mut u64,
- currently_selected_position: u64, is_resized: bool,
+ currently_selected_position: u64, is_force_redraw: bool,
) -> u64 {
- if is_resized {
+ if is_force_redraw {
*scroll_position_bar = 0;
}
diff --git a/src/canvas/widgets/cpu_graph.rs b/src/canvas/widgets/cpu_graph.rs
index cefed8a2..a49bd6ad 100644
--- a/src/canvas/widgets/cpu_graph.rs
+++ b/src/canvas/widgets/cpu_graph.rs
@@ -224,7 +224,7 @@ impl CpuGraphWidget for Painter {
&cpu_widget_state.scroll_state.scroll_direction,
&mut cpu_widget_state.scroll_state.previous_scroll_position,
cpu_widget_state.scroll_state.current_scroll_position,
- app_state.is_resized,
+ app_state.is_force_redraw,
);
let is_on_widget = widget_id == app_state.current_widget.widget_id;
diff --git a/src/canvas/widgets/disk_table.rs b/src/canvas/widgets/disk_table.rs
index 13d24358..fda54d97 100644
--- a/src/canvas/widgets/disk_table.rs
+++ b/src/canvas/widgets/disk_table.rs
@@ -45,7 +45,7 @@ impl DiskTableWidget for Painter {
&disk_widget_state.scroll_state.scroll_direction,
&mut disk_widget_state.scroll_state.previous_scroll_position,
disk_widget_state.scroll_state.current_scroll_position,
- app_state.is_resized,
+ app_state.is_force_redraw,
);
let is_on_widget = app_state.current_widget.widget_id == widget_id;
let disk_table_state = &mut disk_widget_state.scroll_state.table_state;
diff --git a/src/canvas/widgets/process_table.rs b/src/canvas/widgets/process_table.rs
index 0733b500..40803f9b 100644
--- a/src/canvas/widgets/process_table.rs
+++ b/src/canvas/widgets/process_table.rs
@@ -91,7 +91,7 @@ impl ProcessTableWidget for Painter {
&proc_widget_state.scroll_state.scroll_direction,
&mut proc_widget_state.scroll_state.previous_scroll_position,
proc_widget_state.scroll_state.current_scroll_position,
- app_state.is_resized,
+ app_state.is_force_redraw,
);
// Sanity check
@@ -370,7 +370,7 @@ impl ProcessTableWidget for Painter {
.search_state
.cursor_bar,
current_cursor_position,
- app_state.is_resized,
+ app_state.is_force_redraw,
);
let query = proc_widget_state.get_current_search_query().as_str();
diff --git a/src/canvas/widgets/temp_table.rs b/src/canvas/widgets/temp_table.rs
index 007d93b0..1e679904 100644
--- a/