feature: add basic page up/down scrolling (#646)

Adds page up/down scrolling support to respectively scroll up/down by a full page.

Note that this is mostly just to get the feature out for those interested, and is admittedly a bit rushed - I will be rewriting all logic involving event handling as part of state refactor anyways, so this will also get changed in the work done there, and therefore, I kinda just sped through this.
This commit is contained in:
Clement Tsang 2021-12-27 15:23:11 -08:00 committed by GitHub
parent c92cfc644d
commit 9eabb061aa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 86 additions and 44 deletions

View File

@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [0.6.7]/[0.7.0] - Unreleased
## Feature
- [#646](https://github.com/ClementTsang/bottom/pull/646): Add `PgUp`/`PgDown` keybind support to scroll up and down a page in a table.
## [0.6.6] - 2021-12-22
## Bug Fixes

View File

@ -55,6 +55,7 @@ Note that key bindings are generally case-sensitive.
| ++right++ <br/> ++l++ <br/> ++alt+l++ | Move right within a widget |
| ++g+g++ , ++home++ | Jump to the first entry |
| ++G++ , ++end++ | Jump to the last entry |
| ++page-up++ , ++page-down++ | Scroll up/down a table by a page |
## Mouse bindings

View File

@ -1114,6 +1114,20 @@ impl App {
0 => KillSignal::Cancel,
sig => KillSignal::Kill(sig),
};
} else if self.current_widget.widget_type.is_widget_table() {
if let (Some((_tlc_x, tlc_y)), Some((_brc_x, brc_y))) = (
&self.current_widget.top_left_corner,
&self.current_widget.bottom_right_corner,
) {
let border_offset = if self.is_drawing_border() { 1 } else { 0 };
let header_gap_offset = 1 + if self.is_drawing_gap(&self.current_widget) {
self.app_config_fields.table_gap
} else {
0
};
let height = brc_y - tlc_y - 2 * border_offset - header_gap_offset;
self.change_position_count(-(height as i64));
}
}
}
@ -1127,6 +1141,20 @@ impl App {
new_signal += 2;
}
self.delete_dialog_state.selected_signal = KillSignal::Kill(new_signal);
} else if self.current_widget.widget_type.is_widget_table() {
if let (Some((_tlc_x, tlc_y)), Some((_brc_x, brc_y))) = (
&self.current_widget.top_left_corner,
&self.current_widget.bottom_right_corner,
) {
let border_offset = if self.is_drawing_border() { 1 } else { 0 };
let header_gap_offset = 1 + if self.is_drawing_gap(&self.current_widget) {
self.app_config_fields.table_gap
} else {
0
};
let height = brc_y - tlc_y - 2 * border_offset - header_gap_offset;
self.change_position_count(height as i64);
}
}
}
@ -1443,8 +1471,6 @@ impl App {
'0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' => {
self.on_number(caught_char)
}
'u' => self.on_page_up(),
'd' => self.on_page_down(),
'g' => {
let mut is_first_g = true;
if let Some(second_char) = self.second_char {
@ -2330,36 +2356,29 @@ impl App {
}
pub fn decrement_position_count(&mut self) {
if !self.ignore_normal_keybinds() {
match self.current_widget.widget_type {
BottomWidgetType::Proc => {
self.increment_process_position(-1);
}
BottomWidgetType::ProcSort => self.increment_process_sort_position(-1),
BottomWidgetType::Temp => self.increment_temp_position(-1),
BottomWidgetType::Disk => self.increment_disk_position(-1),
BottomWidgetType::CpuLegend => self.increment_cpu_legend_position(-1),
_ => {}
}
}
self.change_position_count(-1);
}
pub fn increment_position_count(&mut self) {
self.change_position_count(1);
}
fn change_position_count(&mut self, amount: i64) {
if !self.ignore_normal_keybinds() {
match self.current_widget.widget_type {
BottomWidgetType::Proc => {
self.increment_process_position(1);
self.change_process_position(amount);
}
BottomWidgetType::ProcSort => self.increment_process_sort_position(1),
BottomWidgetType::Temp => self.increment_temp_position(1),
BottomWidgetType::Disk => self.increment_disk_position(1),
BottomWidgetType::CpuLegend => self.increment_cpu_legend_position(1),
BottomWidgetType::ProcSort => self.change_process_sort_position(amount),
BottomWidgetType::Temp => self.change_temp_position(amount),
BottomWidgetType::Disk => self.increment_disk_position(amount),
BottomWidgetType::CpuLegend => self.change_cpu_legend_position(amount),
_ => {}
}
}
}
fn increment_process_sort_position(&mut self, num_to_change_by: i64) {
fn change_process_sort_position(&mut self, num_to_change_by: i64) {
if let Some(proc_widget_state) = self
.proc_state
.get_mut_widget_state(self.current_widget.widget_id - 2)
@ -2367,9 +2386,11 @@ impl App {
let current_posn = proc_widget_state.columns.current_scroll_position;
let num_columns = proc_widget_state.columns.get_enabled_columns_len();
if current_posn as i64 + num_to_change_by >= 0
&& current_posn as i64 + num_to_change_by < num_columns as i64
{
if current_posn as i64 + num_to_change_by < 0 {
proc_widget_state.columns.current_scroll_position = 0;
} else if current_posn as i64 + num_to_change_by >= num_columns as i64 {
proc_widget_state.columns.current_scroll_position = num_columns.saturating_sub(1);
} else {
proc_widget_state.columns.current_scroll_position =
(current_posn as i64 + num_to_change_by) as usize;
}
@ -2382,7 +2403,7 @@ impl App {
}
}
fn increment_cpu_legend_position(&mut self, num_to_change_by: i64) {
fn change_cpu_legend_position(&mut self, num_to_change_by: i64) {
if let Some(cpu_widget_state) = self
.cpu_state
.widget_states
@ -2391,9 +2412,11 @@ impl App {
let current_posn = cpu_widget_state.scroll_state.current_scroll_position;
let cap = self.canvas_data.cpu_data.len();
if current_posn as i64 + num_to_change_by >= 0
&& current_posn as i64 + num_to_change_by < cap as i64
{
if current_posn as i64 + num_to_change_by < 0 {
cpu_widget_state.scroll_state.current_scroll_position = 0;
} else if current_posn as i64 + num_to_change_by >= cap as i64 {
cpu_widget_state.scroll_state.current_scroll_position = cap.saturating_sub(1);
} else {
cpu_widget_state.scroll_state.current_scroll_position =
(current_posn as i64 + num_to_change_by) as usize;
}
@ -2407,7 +2430,7 @@ impl App {
}
/// Returns the new position.
fn increment_process_position(&mut self, num_to_change_by: i64) -> Option<usize> {
fn change_process_position(&mut self, num_to_change_by: i64) -> Option<usize> {
if let Some(proc_widget_state) = self
.proc_state
.get_mut_widget_state(self.current_widget.widget_id)
@ -2418,13 +2441,16 @@ impl App {
.finalized_process_data_map
.get(&self.current_widget.widget_id)
{
if current_posn as i64 + num_to_change_by >= 0
&& current_posn as i64 + num_to_change_by < finalized_process_data.len() as i64
if current_posn as i64 + num_to_change_by < 0 {
proc_widget_state.scroll_state.current_scroll_position = 0;
} else if current_posn as i64 + num_to_change_by
>= finalized_process_data.len() as i64
{
proc_widget_state.scroll_state.current_scroll_position =
(current_posn as i64 + num_to_change_by) as usize;
finalized_process_data.len().saturating_sub(1);
} else {
return None;
proc_widget_state.scroll_state.current_scroll_position =
(current_posn as i64 + num_to_change_by) as usize;
}
}
@ -2440,7 +2466,7 @@ impl App {
None
}
fn increment_temp_position(&mut self, num_to_change_by: i64) {
fn change_temp_position(&mut self, num_to_change_by: i64) {
if let Some(temp_widget_state) = self
.temp_state
.widget_states
@ -2448,10 +2474,14 @@ impl App {
{
let current_posn = temp_widget_state.scroll_state.current_scroll_position;
if current_posn as i64 + num_to_change_by >= 0
&& current_posn as i64 + num_to_change_by
< self.canvas_data.temp_sensor_data.len() as i64
if current_posn as i64 + num_to_change_by < 0 {
temp_widget_state.scroll_state.current_scroll_position = 0;
} else if current_posn as i64 + num_to_change_by
>= self.canvas_data.temp_sensor_data.len() as i64
{
temp_widget_state.scroll_state.current_scroll_position =
self.canvas_data.temp_sensor_data.len().saturating_sub(1);
} else {
temp_widget_state.scroll_state.current_scroll_position =
(current_posn as i64 + num_to_change_by) as usize;
}
@ -2901,9 +2931,6 @@ impl App {
}
let mut failed_to_get = true;
// TODO: [MOUSE] We could use a better data structure for this? Currently it's a blind
// traversal through a hashmap, using a 2d binary tree of sorts would be better.
// See: https://docs.rs/kdtree/0.6.0/kdtree/
for (new_widget_id, widget) in &self.widget_map {
if let (Some((tlc_x, tlc_y)), Some((brc_x, brc_y))) =
(widget.top_left_corner, widget.bottom_right_corner)
@ -2985,7 +3012,7 @@ impl App {
.current_scroll_position;
let is_tree_mode = proc_widget_state.is_tree_mode;
let new_position = self.increment_process_position(
let new_position = self.change_process_position(
offset_clicked_entry as i64 - visual_index as i64,
);
@ -3008,7 +3035,7 @@ impl App {
if let Some(visual_index) =
proc_widget_state.columns.column_state.selected()
{
self.increment_process_sort_position(
self.change_process_sort_position(
offset_clicked_entry as i64 - visual_index as i64,
);
}
@ -3022,7 +3049,7 @@ impl App {
if let Some(visual_index) =
cpu_widget_state.scroll_state.table_state.selected()
{
self.increment_cpu_legend_position(
self.change_cpu_legend_position(
offset_clicked_entry as i64 - visual_index as i64,
);
}
@ -3036,7 +3063,7 @@ impl App {
if let Some(visual_index) =
temp_widget_state.scroll_state.table_state.selected()
{
self.increment_temp_position(
self.change_temp_position(
offset_clicked_entry as i64 - visual_index as i64,
);
}

View File

@ -695,6 +695,13 @@ impl Painter {
}
})?;
if let Some(updated_current_widget) = app_state
.widget_map
.get(&app_state.current_widget.widget_id)
{
app_state.current_widget = updated_current_widget.clone();
}
app_state.is_force_redraw = false;
app_state.is_determining_widget_boundary = false;

View File

@ -231,7 +231,7 @@ pub const HELP_CONTENTS_TEXT: [&str; 8] = [
// TODO [Help]: Search in help?
// TODO [Help]: Move to using tables for easier formatting?
pub const GENERAL_HELP_TEXT: [&str; 30] = [
pub const GENERAL_HELP_TEXT: [&str; 31] = [
"1 - General",
"q, Ctrl-c Quit",
"Esc Close dialog windows, search, widgets, or exit expanded mode",
@ -260,6 +260,7 @@ pub const GENERAL_HELP_TEXT: [&str; 30] = [
"+ Zoom in on chart (decrease time range)",
"- Zoom out on chart (increase time range)",
"= Reset zoom",
"PgUp, PgDown Scroll up/down a table by a page",
"Mouse scroll Scroll through the tables or zoom in/out of charts by scrolling up/down",
"Mouse click Selects the clicked widget, table entry, dialog option, or tab",
];

View File

@ -125,6 +125,8 @@ 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(),
KeyCode::PageDown => app.on_page_down(),
KeyCode::PageUp => app.on_page_up(),
_ => {}
}
} else {