From 132a5a2170294f0d5c463ecba77de1aab32183db Mon Sep 17 00:00:00 2001 From: Clement Tsang <34804052+ClementTsang@users.noreply.github.com> Date: Thu, 5 Mar 2020 23:54:39 -0500 Subject: 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. --- src/app.rs | 2 + src/app/data_harvester/network.rs | 10 +- src/canvas.rs | 211 +++++++++++++++++++++++--------------- src/canvas/drawing_utils.rs | 1 - src/constants.rs | 18 ++-- 5 files changed, 148 insertions(+), 94 deletions(-) (limited to 'src') diff --git a/src/app.rs b/src/app.rs index 641e4cee..8033d227 100644 --- a/src/app.rs +++ b/src/app.rs @@ -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 { diff --git a/src/app/data_harvester/network.rs b/src/app/data_harvester/network.rs index 2c2dba7d..c425ccd6 100644 --- a/src/app/data_harvester/network.rs +++ b/src/app/data_harvester/network.rs @@ -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; diff --git a/src/canvas.rs b/src/canvas.rs index 199ad0b8..8c0c9545 100644 --- a/src/canvas.rs +++ b/src/canvas.rs @@ -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( &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::>() }; - 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; diff --git a/src/canvas/drawing_utils.rs b/src/canvas/drawing_utils.rs index c242e6fd..f855ba13 100644 --- a/src/canvas/drawing_utils.rs +++ b/src/canvas/drawing_utils.rs @@ -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, diff --git a/src/constants.rs b/src/constants.rs index 3ccc7b32..7453c7d5 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -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 -- cgit v1.2.3