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.
This commit is contained in:
parent
255b69c15f
commit
6c989785fb
|
@ -19,7 +19,7 @@ path = "src/bin/main.rs"
|
|||
doc = false
|
||||
|
||||
[lib]
|
||||
test = false
|
||||
test = true
|
||||
doctest = false
|
||||
doc = false
|
||||
|
||||
|
|
129
src/canvas.rs
129
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,
|
||||
);
|
||||
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,
|
||||
),
|
||||
_ => {}
|
||||
}
|
||||
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,
|
||||
),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
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,
|
||||
),
|
||||
_ => {}
|
||||
}
|
||||
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,
|
||||
),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,94 +35,83 @@ 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()
|
||||
};
|
||||
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()
|
||||
};
|
||||
|
||||
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);
|
||||
|
||||
// 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);
|
||||
} 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;
|
||||
}
|
||||
|
||||
column_widths[*itx] = space_taken;
|
||||
total_width_left -= space_taken;
|
||||
total_width_left = total_width_left.saturating_sub(1);
|
||||
}
|
||||
}
|
||||
|
||||
// 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 {
|
||||
if let Some(Some(hard_width)) = hard_widths.get(*itx) {
|
||||
// Hard width...
|
||||
let space_taken = min(*hard_width, total_width_left);
|
||||
|
||||
// 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);
|
||||
} 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;
|
||||
}
|
||||
|
||||
column_widths[*itx] = space_taken;
|
||||
total_width_left -= space_taken;
|
||||
total_width_left = total_width_left.saturating_sub(1);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
column_widths
|
||||
} else {
|
||||
vec![]
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
} 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![]
|
||||
// }
|
||||
|
||||
pub fn get_search_start_position(
|
||||
num_columns: usize, cursor_direction: &app::CursorDirection, cursor_bar: &mut usize,
|
||||
current_cursor_position: usize, is_force_redraw: bool,
|
||||
|
@ -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"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue