Fix dialog box height and scroll label (#71)

* Fixes search with small mode by changing the prompt based on size.

* Minor fixes for search

- Remove ignore unused var lint
- Add a bit more spacing to deal with large unicode
- Add on-right movement on type

* Add contributor's list and bug/req section

* Check for div by zero

* Fix for dd in terms of sizing.

* Added (temporary) fix for help box.  Scrolling is the ideal solution but will leave that for another time.
This commit is contained in:
Clement Tsang 2020-03-05 23:54:39 -05:00 committed by GitHub
parent e16eb832fc
commit 132a5a2170
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 158 additions and 94 deletions

View File

@ -210,12 +210,22 @@ Note that `q` is disabled while in the search widget.
- Scrolling with the mouse will scroll through the currently selected list if the widget is a scrollable table.
## Bugs and Requests
Spot an bug? Have an idea? Leave an issue that explains what you want in detail and I'll try to take a look.
## Contribution
Contribution is welcome! Just submit a PR. Note that I develop and test on stable Rust.
If you spot any issue with nobody assigned to it, or it seems like no work has started on it, feel free to try and do it!
### Contributors
Thanks to those who have contributed:
- [shilangyu](https://github.com/shilangyu)
## Thanks, kudos, and all the like
- This project is very much inspired by both [gotop](https://github.com/cjbassi/gotop) and [gtop](https://github.com/aksakalli/gtop).

View File

@ -945,6 +945,8 @@ impl App {
self.update_regex();
self.update_process_gui = true;
self.process_search_state.search_state.cursor_direction =
CursorDirection::RIGHT;
}
} else {
match caught_char {

View File

@ -45,8 +45,14 @@ pub async fn get_network_data(
let elapsed_time = curr_time.duration_since(prev_net_access_time).as_secs_f64();
let rx = ((total_rx - *prev_net_rx) as f64 / elapsed_time) as u64;
let tx = ((total_tx - *prev_net_tx) as f64 / elapsed_time) as u64;
let (rx, tx) = if elapsed_time == 0.0 {
(0, 0)
} else {
(
((total_rx - *prev_net_rx) as f64 / elapsed_time) as u64,
((total_tx - *prev_net_tx) as f64 / elapsed_time) as u64,
)
};
*prev_net_rx = total_rx;
*prev_net_tx = total_tx;

View File

@ -187,31 +187,44 @@ impl Painter {
terminal.autoresize()?;
terminal.draw(|mut f| {
debug!("{:?}", f.size());
if app_state.help_dialog_state.is_showing_help {
// Only for the help
// TODO: [RESIZE] Scrolling dialog boxes is ideal. This is currently VERY temporary!
// The width is currently not good and can wrap... causing this to not go so well!
let gen_help_len = GENERAL_HELP_TEXT.len() as u16 + 3;
let border_len = (max(0, f.size().height as i64 - gen_help_len as i64)) as u16 / 2;
let vertical_dialog_chunk = Layout::default()
.direction(Direction::Vertical)
.margin(1)
.constraints(
[
Constraint::Percentage(20),
Constraint::Percentage(60),
Constraint::Percentage(20),
Constraint::Length(border_len),
Constraint::Length(gen_help_len),
Constraint::Length(border_len),
]
.as_ref(),
.as_ref(),
)
.split(f.size());
let middle_dialog_chunk = Layout::default()
.direction(Direction::Horizontal)
.margin(0)
.constraints(
[
Constraint::Percentage(20),
Constraint::Percentage(60),
Constraint::Percentage(20),
]
.as_ref(),
if f.size().width < 100 {
// TODO: [REFACTOR] The point we start changing size at currently hard-coded in.
[
Constraint::Percentage(0),
Constraint::Percentage(100),
Constraint::Percentage(0),
]
} else {
[
Constraint::Percentage(20),
Constraint::Percentage(60),
Constraint::Percentage(20),
]
}
.as_ref(),
)
.split(vertical_dialog_chunk[1]);
@ -232,44 +245,52 @@ impl Painter {
app::AppHelpCategory::Process => &self.styled_process_help_text,
app::AppHelpCategory::Search => &self.styled_search_help_text,
}
.iter(),
.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)
.render(&mut f, middle_dialog_chunk[1]);
.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)
.render(&mut f, middle_dialog_chunk[1]);
} else if app_state.delete_dialog_state.is_showing_dd {
let bordering = (max(0, f.size().height as i64 - 7) as u16) / 2;
let vertical_dialog_chunk = Layout::default()
.direction(Direction::Vertical)
.margin(1)
.constraints(
[
Constraint::Percentage(35),
Constraint::Percentage(30),
Constraint::Percentage(35),
Constraint::Length(bordering),
Constraint::Length(7),
Constraint::Length(bordering),
]
.as_ref(),
.as_ref(),
)
.split(f.size());
let middle_dialog_chunk = Layout::default()
.direction(Direction::Horizontal)
.margin(0)
.constraints(
[
Constraint::Percentage(25),
Constraint::Percentage(50),
Constraint::Percentage(25),
]
.as_ref(),
if f.size().width < 100 {
// TODO: [REFACTOR] The point we start changing size at currently hard-coded in.
[
Constraint::Percentage(5),
Constraint::Percentage(90),
Constraint::Percentage(5),
]
} else {
[
Constraint::Percentage(30),
Constraint::Percentage(40),
Constraint::Percentage(30),
]
}
.as_ref(),
)
.split(vertical_dialog_chunk[1]);
@ -306,22 +327,24 @@ impl Painter {
if app_state.is_grouped() {
if to_kill_processes.1.len() != 1 {
Text::raw(format!(
"\nAre you sure you want to kill {} processes with the name {}?",
to_kill_processes.1.len(), to_kill_processes.0
"\nKill {} processes with the name {}?",
to_kill_processes.1.len(),
to_kill_processes.0
))
} else {
Text::raw(format!(
"\nAre you sure you want to kill {} process with the name {}?",
to_kill_processes.1.len(), to_kill_processes.0
"\nKill {} process with the name {}?",
to_kill_processes.1.len(),
to_kill_processes.0
))
}
} else {
Text::raw(format!(
"\nAre you sure you want to kill process {} with PID {}?",
"\nKill process {} with PID {}?",
to_kill_processes.0, first_pid
))
},
Text::raw("\nNote that if bottom is frozen, it must be unfrozen for changes to be shown.\n\n\n"),
Text::raw("\n\n"),
if app_state.delete_dialog_state.is_on_yes {
Text::styled("Yes", self.colours.currently_selected_text_style)
} else {
@ -339,7 +362,8 @@ impl Painter {
let repeat_num = max(
0,
middle_dialog_chunk[1].width as i32
- DD_BASE.chars().count() as i32 - 2,
- DD_BASE.chars().count() as i32
- 2,
);
let dd_title = format!(
" Confirm Kill Process ─{}─ Esc to close ",
@ -424,39 +448,49 @@ impl Painter {
// the same info.
let cpu_height = (app_state.canvas_data.cpu_data.len() / 4) as u16
+ (
if app_state.canvas_data.cpu_data.len() % 4 == 0 {
+ (if app_state.canvas_data.cpu_data.len() % 4 == 0 {
0
} else {
1
}
);
});
let vertical_chunks = Layout::default()
.direction(Direction::Vertical)
.constraints([
Constraint::Length(cpu_height),
Constraint::Length(1),
Constraint::Length(2),
Constraint::Length(2),
Constraint::Min(5),
].as_ref())
.constraints(
[
Constraint::Length(cpu_height),
Constraint::Length(1),
Constraint::Length(2),
Constraint::Length(2),
Constraint::Min(5),
]
.as_ref(),
)
.split(f.size());
let middle_chunks = Layout::default()
.direction(Direction::Horizontal)
.constraints([
Constraint::Percentage(50),
Constraint::Percentage(50),
].as_ref())
.constraints([Constraint::Percentage(50), Constraint::Percentage(50)].as_ref())
.split(vertical_chunks[2]);
self.draw_basic_cpu(&mut f, app_state, vertical_chunks[0]);
self.draw_basic_memory(&mut f, app_state, middle_chunks[0]);
self.draw_basic_network(&mut f, app_state, middle_chunks[1]);
self.draw_basic_table_arrows(&mut f, app_state, vertical_chunks[3]);
if app_state.current_widget_selected.is_widget_table() {
self.draw_specific_table(&mut f, app_state, vertical_chunks[4], false, app_state.current_widget_selected);
self.draw_specific_table(
&mut f,
app_state,
vertical_chunks[4],
false,
app_state.current_widget_selected,
);
} else {
self.draw_specific_table(&mut f, app_state, vertical_chunks[4], false, app_state.previous_basic_table_selected);
self.draw_specific_table(
&mut f,
app_state,
vertical_chunks[4],
false,
app_state.previous_basic_table_selected,
);
}
} else {
// TODO: [TUI] Change this back to a more even 33/33/34 when TUI releases
@ -469,7 +503,7 @@ impl Painter {
Constraint::Percentage(37),
Constraint::Percentage(33),
]
.as_ref(),
.as_ref(),
)
.split(f.size());
@ -501,7 +535,7 @@ impl Painter {
} else {
[Constraint::Percentage(85), Constraint::Percentage(15)]
}
.as_ref(),
.as_ref(),
)
.split(vertical_chunks[0]);
@ -520,7 +554,7 @@ impl Painter {
let remaining = bottom_chunks[0].height - required;
[Constraint::Length(remaining), Constraint::Length(required)]
}
.as_ref(),
.as_ref(),
)
.split(bottom_chunks[0]);
@ -1247,15 +1281,39 @@ impl Painter {
fn draw_search_field<B: Backend>(
&self, f: &mut Frame<'_, B>, app_state: &mut app::App, draw_loc: Rect, draw_border: bool,
) {
let width = max(0, draw_loc.width as i64 - 34) as u64; // TODO: [REFACTOR] Hard coding this is terrible.
let pid_search_text = "Search by PID (Tab for Name): ";
let name_search_text = "Search by Name (Tab for PID): ";
let grouped_search_text = "Search by Name: ";
let num_columns = draw_loc.width as usize;
let chosen_text = if app_state.is_grouped() {
grouped_search_text
} else if app_state.process_search_state.is_searching_with_pid {
pid_search_text
} else {
name_search_text
};
let search_title: &str = if chosen_text.len() == min(num_columns / 2, chosen_text.len()) {
chosen_text
} else if chosen_text.is_empty() {
""
} else {
"> "
};
let num_chars_for_text = search_title.len();
let mut search_text = vec![Text::styled(search_title, self.colours.table_header_style)];
let cursor_position = app_state.get_cursor_position();
let char_cursor_position = app_state.get_char_cursor_position();
let current_cursor_position = app_state.get_char_cursor_position();
let start_position: usize = get_search_start_position(
width as usize,
num_columns - num_chars_for_text - 5,
&app_state.process_search_state.search_state.cursor_direction,
&mut app_state.process_search_state.search_state.cursor_bar,
char_cursor_position,
current_cursor_position,
app_state.is_resized,
);
@ -1305,20 +1363,6 @@ impl Painter {
.collect::<Vec<_>>()
};
let mut search_text = vec![if app_state.is_grouped() {
Text::styled("Search by Name: ", self.colours.table_header_style)
} else if app_state.process_search_state.is_searching_with_pid {
Text::styled(
"Search by PID (Tab for Name): ",
self.colours.table_header_style,
)
} else {
Text::styled(
"Search by Name (Tab for PID): ",
self.colours.table_header_style,
)
}];
// Text options shamelessly stolen from VS Code.
let mut option_text = vec![];
let case_style = if !app_state.process_search_state.is_ignoring_case {
@ -1658,7 +1702,8 @@ impl Painter {
let margin_space = 2;
let remaining_width = max(
0,
draw_loc.width as i64 - ((9 + margin_space) * REQUIRED_COLUMNS) as i64,
draw_loc.width as i64
- ((9 + margin_space) * REQUIRED_COLUMNS - margin_space) as i64,
) as usize;
let bar_length = remaining_width / REQUIRED_COLUMNS;

View File

@ -70,7 +70,6 @@ pub fn get_variable_intrinsic_widths(
(resulting_widths, last_index)
}
#[allow(dead_code, unused_variables)]
pub fn get_search_start_position(
num_columns: usize, cursor_direction: &app::CursorDirection, cursor_bar: &mut usize,
current_cursor_position: usize, is_resized: bool,

View File

@ -1,16 +1,13 @@
pub const STALE_MAX_MILLISECONDS: u128 = 60 * 1000;
// How long to store data.
pub const STALE_MAX_MILLISECONDS: u128 = 60 * 1000;
pub const TIME_STARTS_FROM: u64 = 60 * 1000;
pub const TICK_RATE_IN_MILLISECONDS: u64 = 200;
// How fast the screen refreshes
pub const DEFAULT_REFRESH_RATE_IN_MILLISECONDS: u128 = 1000;
pub const MAX_KEY_TIMEOUT_IN_MILLISECONDS: u128 = 1000;
// Number of colours to generate for the CPU chart/table
pub const NUM_COLOURS: i32 = 256;
// Config and flags
pub const DEFAULT_UNIX_CONFIG_FILE_PATH: &str = ".config/bottom/bottom.toml";
pub const DEFAULT_WINDOWS_CONFIG_FILE_PATH: &str = "bottom/bottom.toml";
// Help text
pub const GENERAL_HELP_TEXT: [&str; 15] = [
"General Keybindings\n\n",
@ -18,9 +15,9 @@ pub const GENERAL_HELP_TEXT: [&str; 15] = [
"Esc Close filters, dialog boxes, etc.\n",
"Ctrl-r Reset all data\n",
"f Freeze display\n",
"Ctrl-Arrow Move currently selected widget\n",
"Shift-Arrow Move currently selected widget\n",
"H/J/K/L Move currently selected widget up/down/left/right\n",
"Ctrl-Arrow Change your selected widget\n",
"Shift-Arrow Change your selected widget\n",
"H/J/K/L Change your selected widget up/down/left/right\n",
"Up, k Move cursor up\n",
"Down, j Move cursor down\n",
"? Open the help screen\n",
@ -57,6 +54,11 @@ pub const SEARCH_HELP_TEXT: [&str; 13] = [
"Alt-r/F3 Toggle whether to use regex\n",
];
// Config and flags
pub const DEFAULT_UNIX_CONFIG_FILE_PATH: &str = ".config/bottom/bottom.toml";
pub const DEFAULT_WINDOWS_CONFIG_FILE_PATH: &str = "bottom/bottom.toml";
// Default config file
pub const DEFAULT_CONFIG_CONTENT: &str = r##"
# This is a default config file for bottom. All of the settings are commented
# out by default; if you wish to change them uncomment and modify as you see