diff options
author | Clement Tsang <34804052+ClementTsang@users.noreply.github.com> | 2022-01-27 16:16:27 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-01-27 19:16:27 -0500 |
commit | 6c989785fb458a8d7933f98050148e0faf45a8ba (patch) | |
tree | 94562a1e352cb7edcb537576c4b60e62117b13b9 | |
parent | 255b69c15fa3d997737c5e1b51d480c45cb0fe4d (diff) |
bug: fix issues caused by having a width that is too small (#665)
Due to a missing check, you could resize the window to a width that was too small, and it would trigger an endless while-loop for any table while trying to redistribute remaining space. This has been rectified with an explicit check, as well as a smarter method of redistributing remaining space borrowed from the rewrite.
This also adds explicit width checks for widgets that have borders; if the width is <2, before, it would panic.
Note that the rewrite I have kinda fixes all these issues already, so I don't want to invest too hard into this, but this should be fine as a patch for now.
Also note that minimal heights don't seem to be causing any issues, it just seems to be minimal widths.
-rw-r--r-- | Cargo.toml | 2 | ||||
-rw-r--r-- | src/canvas.rs | 129 | ||||
-rw-r--r-- | src/canvas/drawing_utils.rs | 192 |
3 files changed, 191 insertions, 132 deletions
@@ -19,7 +19,7 @@ path = "src/bin/main.rs" doc = false [lib] -test = false +test = true doctest = false doc = false diff --git a/src/canvas.rs b/src/canvas.rs index 4648a417..447d9421 100644 --- a/src/canvas.rs +++ b/src/canvas.rs @@ -282,9 +282,6 @@ impl Painter { self.styled_help_text = styled_help_spans.into_iter().map(Spans::from).collect(); } - // FIXME: [CONFIG] write this, should call painter init and any changed colour functions... - pub fn update_painter_colours(&mut self) {} - fn draw_frozen_indicator<B: Backend>(&self, f: &mut Frame<'_, B>, draw_loc: Rect) { f.render_widget( Paragraph::new(Span::styled( @@ -559,44 +556,62 @@ impl Painter { .direction(Direction::Horizontal) .constraints([Constraint::Percentage(50), Constraint::Percentage(50)]) .split(vertical_chunks[1]); - self.draw_basic_cpu(f, app_state, vertical_chunks[0], 1); - self.draw_basic_memory(f, app_state, middle_chunks[0], 2); - self.draw_basic_network(f, app_state, middle_chunks[1], 3); + + if vertical_chunks[0].width >= 2 { + self.draw_basic_cpu(f, app_state, vertical_chunks[0], 1); + } + if middle_chunks[0].width >= 2 { + self.draw_basic_memory(f, app_state, middle_chunks[0], 2); + } + if middle_chunks[1].width >= 2 { + self.draw_basic_network(f, app_state, middle_chunks[1], 3); + } let mut later_widget_id: Option<u64> = None; if let Some(basic_table_widget_state) = &app_state.basic_table_widget_state { let widget_id = basic_table_widget_state.currently_displayed_widget_id; later_widget_id = Some(widget_id); - match basic_table_widget_state.currently_displayed_widget_type { - Disk => { - self.draw_disk_table(f, app_state, vertical_chunks[3], false, widget_id) - } - Proc | ProcSort => { - let wid = widget_id - - match basic_table_widget_state.currently_displayed_widget_type { - ProcSearch => 1, - ProcSort => 2, - _ => 0, - }; - self.draw_process_features( + if vertical_chunks[3].width >= 2 { + match basic_table_widget_state.currently_displayed_widget_type { + Disk => self.draw_disk_table( f, app_state, vertical_chunks[3], false, - wid, - ); - } - Temp => { - self.draw_temp_table(f, app_state, vertical_chunks[3], false, widget_id) + widget_id, + ), + Proc | ProcSort => { + let wid = widget_id + - match basic_table_widget_state.currently_displayed_widget_type + { + ProcSearch => 1, + ProcSort => 2, + _ => 0, + }; + self.draw_process_features( + f, + app_state, + vertical_chunks[3], + false, + wid, + ); + } + Temp => self.draw_temp_table( + f, + app_state, + vertical_chunks[3], + false, + widget_id, + ), + Battery => self.draw_battery_display( + f, + app_state, + vertical_chunks[3], + false, + widget_id, + ), + _ => {} } - Battery => self.draw_battery_display( - f, - app_state, - vertical_chunks[3], - false, - widget_id, - ), - _ => {} } } @@ -712,32 +727,34 @@ impl Painter { ) { use BottomWidgetType::*; for (widget, widget_draw_loc) in widgets.children.iter().zip(widget_draw_locs) { - match &widget.widget_type { - Empty => {} - Cpu => self.draw_cpu(f, app_state, *widget_draw_loc, widget.widget_id), - Mem => self.draw_memory_graph(f, app_state, *widget_draw_loc, widget.widget_id), - Net => self.draw_network(f, app_state, *widget_draw_loc, widget.widget_id), - Temp => { - self.draw_temp_table(f, app_state, *widget_draw_loc, true, widget.widget_id) - } - Disk => { - self.draw_disk_table(f, app_state, *widget_draw_loc, true, widget.widget_id) + if widget_draw_loc.width >= 2 && widget_draw_loc.height >= 2 { + match &widget.widget_type { + Empty => {} + Cpu => self.draw_cpu(f, app_state, *widget_draw_loc, widget.widget_id), + Mem => self.draw_memory_graph(f, app_state, *widget_draw_loc, widget.widget_id), + Net => self.draw_network(f, app_state, *widget_draw_loc, widget.widget_id), + Temp => { + self.draw_temp_table(f, app_state, *widget_draw_loc, true, widget.widget_id) + } + Disk => { + self.draw_disk_table(f, app_state, *widget_draw_loc, true, widget.widget_id) + } + Proc => self.draw_process_features( + f, + app_state, + *widget_draw_loc, + true, + widget.widget_id, + ), + Battery => self.draw_battery_display( + f, + app_state, + *widget_draw_loc, + true, + widget.widget_id, + ), + _ => {} } - Proc => self.draw_process_features( - f, - app_state, - *widget_draw_loc, - true, - widget.widget_id, - ), - Battery => self.draw_battery_display( - f, - app_state, - *widget_draw_loc, - true, - widget.widget_id, - ), - _ => {} } } } diff --git a/src/canvas/drawing_utils.rs b/src/canvas/drawing_utils.rs index ee81127a..129a80a9 100644 --- a/src/canvas/drawing_utils.rs +++ b/src/canvas/drawing_utils.rs @@ -35,93 +35,82 @@ pub fn get_column_widths( "soft width max length != soft width desired length!" ); - let initial_width = total_width - 2; - let mut total_width_left = initial_width; - let mut column_widths: Vec<u16> = vec![0; hard_widths.len()]; - let range: Vec<usize> = if left_to_right { - (0..hard_widths.len()).collect() - } else { - (0..hard_widths.len()).rev().collect() - }; - - for itx in &range { - if let Some(Some(hard_width)) = hard_widths.get(*itx) { - // Hard width... - let space_taken = min(*hard_width, total_width_left); + if total_width > 2 { + let initial_width = total_width - 2; + let mut total_width_left = initial_width; + let mut column_widths: Vec<u16> = vec![0; hard_widths.len()]; + let range: Vec<usize> = if left_to_right { + (0..hard_widths.len()).collect() + } else { + (0..hard_widths.len()).rev().collect() + }; - // TODO [COLUMN MOVEMENT]: Remove this - if *hard_width > space_taken { - break; - } + for itx in &range { + if let Some(Some(hard_width)) = hard_widths.get(*itx) { + // Hard width... + let space_taken = min(*hard_width, total_width_left); - column_widths[*itx] = space_taken; - total_width_left -= space_taken; - total_width_left = total_width_left.saturating_sub(1); - } else if let ( - Some(Some(soft_width_max)), - Some(Some(soft_width_min)), - Some(Some(soft_width_desired)), - ) = ( - soft_widths_max.get(*itx), - soft_widths_min.get(*itx), - soft_widths_desired.get(*itx), - ) { - // Soft width... - let soft_limit = max( - if soft_width_max.is_sign_negative() { - *soft_width_desired - } else { - (*soft_width_max * initial_width as f64).ceil() as u16 - }, - *soft_width_min, - ); - let space_taken = min(min(soft_limit, *soft_width_desired), total_width_left); - - // TODO [COLUMN MOVEMENT]: Remove this - if *soft_width_min > space_taken { - break; - } + // TODO [COLUMN MOVEMENT]: Remove this + if *hard_width > space_taken { + break; + } - column_widths[*itx] = space_taken; - total_width_left -= space_taken; - total_width_left = total_width_left.saturating_sub(1); - } - } + column_widths[*itx] = space_taken; + total_width_left -= space_taken; + total_width_left = total_width_left.saturating_sub(1); + } else if let ( + Some(Some(soft_width_max)), + Some(Some(soft_width_min)), + Some(Some(soft_width_desired)), + ) = ( + soft_widths_max.get(*itx), + soft_widths_min.get(*itx), + soft_widths_desired.get(*itx), + ) { + // Soft width... + let soft_limit = max( + if soft_width_max.is_sign_negative() { + *soft_width_desired + } else { + (*soft_width_max * initial_width as f64).ceil() as u16 + }, + *soft_width_min, + ); + let space_taken = min(min(soft_limit, *soft_width_desired), total_width_left); - // Redistribute remaining. - while total_width_left > 0 { - for itx in &range { - if column_widths[*itx] > 0 { - column_widths[*itx] += 1; - total_width_left -= 1; - if total_width_left == 0 { + // TODO [COLUMN MOVEMENT]: Remove this + if *soft_width_min > space_taken { break; } + + column_widths[*itx] = space_taken; + total_width_left -= space_taken; + total_width_left = total_width_left.saturating_sub(1); } } - } - let mut filtered_column_widths: Vec<u16> = vec![]; - let mut still_seeing_zeros = true; - column_widths.iter().rev().for_each(|width| { - if still_seeing_zeros { - if *width != 0 { - still_seeing_zeros = false; - filtered_column_widths.push(*width); + while let Some(0) = column_widths.last() { + column_widths.pop(); + } + + if !column_widths.is_empty() { + // Redistribute remaining. + let amount_per_slot = total_width_left / column_widths.len() as u16; + total_width_left %= column_widths.len() as u16; + for (index, width) in column_widths.iter_mut().enumerate() { + if (index as u16) < total_width_left { + *width += amount_per_slot + 1; + } else { + *width += amount_per_slot; + } } - } else { - filtered_column_widths.push(*width); } - }); - filtered_column_widths.reverse(); - filtered_column_widths -} -/// FIXME: [command move] This is a greedy method of determining column widths. This is reserved for columns where we are okay with -/// shoving information as far right as required. -// pub fn greedy_get_column_widths() -> Vec<u16> { -// vec![] -// } + column_widths + } else { + vec![] + } +} pub fn get_search_start_position( num_columns: usize, cursor_direction: &app::CursorDirection, cursor_bar: &mut usize, @@ -216,3 +205,56 @@ pub fn interpolate_points(point_one: &(f64, f64), point_two: &(f64, f64), time: (point_one.1 + (time - point_one.0) * slope).max(0.0) } + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_zero_width() { + assert_eq!( + get_column_widths( + 0, + &[Some(1), None, None], + &[None, Some(1), Some(2)], + &[None, Some(0.125), Some(0.5)], + &[None, Some(10), Some(10)], + true + ), + vec![], + "vector should be empty" + ); + } + + #[test] + fn test_two_width() { + assert_eq!( + get_column_widths( + 2, + &[Some(1), None, None], + &[None, Some(1), Some(2)], + &[None, Some(0.125), Some(0.5)], + &[None, Some(10), Some(10)], + true + ), + vec![], + "vector should be empty" + ); + } + + #[test] + fn test_non_zero_width() { + assert_eq!( + get_column_widths( + 16, + &[Some(1), None, None], + &[None, Some(1), Some(2)], + &[None, Some(0.125), Some(0.5)], + &[None, Some(10), Some(10)], + true + ), + vec![2, 2, 7], + "vector should not be empty" + ); + } +} |