bug: fix incorrect offset for cpu list in cpu basic widget (#289)

Fixes the CPU basic widget showing incorrect data due to an incorrect offset when displaying the data.
This commit is contained in:
Clement Tsang 2020-11-02 20:59:54 -05:00 committed by GitHub
parent 5df1764e90
commit 3d9c6b757f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 98 additions and 90 deletions

View File

@ -46,6 +46,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- [#262](https://github.com/ClementTsang/bottom/pull/262): Fixed missing thread termination steps as well as improper polling causing blocking in input thread. - [#262](https://github.com/ClementTsang/bottom/pull/262): Fixed missing thread termination steps as well as improper polling causing blocking in input thread.
- [#289](https://github.com/ClementTsang/bottom/pull/289): Fixed the CPU basic widget showing incorrect data due to an incorrect offset when displaying the data.
- [#290](https://github.com/ClementTsang/bottom/pull/290): Fixed an incorrect offset affecting the CPU colour when scrolling.
## [0.4.7] - 2020-08-26 ## [0.4.7] - 2020-08-26
### Bug Fixes ### Bug Fixes

View File

@ -25,110 +25,114 @@ impl CpuBasicWidget for Painter {
fn draw_basic_cpu<B: Backend>( fn draw_basic_cpu<B: Backend>(
&self, f: &mut Frame<'_, B>, app_state: &mut App, draw_loc: Rect, widget_id: u64, &self, f: &mut Frame<'_, B>, app_state: &mut App, draw_loc: Rect, widget_id: u64,
) { ) {
let cpu_data: &[ConvertedCpuData] = &app_state.canvas_data.cpu_data; // Skip the first element, it's the "all" element
if !app_state.canvas_data.cpu_data.is_empty() {
let cpu_data: &[ConvertedCpuData] = &app_state.canvas_data.cpu_data[1..];
// This is a bit complicated, but basically, we want to draw SOME number // This is a bit complicated, but basically, we want to draw SOME number
// of columns to draw all CPUs. Ideally, as well, we want to not have // of columns to draw all CPUs. Ideally, as well, we want to not have
// to ever scroll. // to ever scroll.
// **General logic** - count number of elements in cpu_data. Then see how // **General logic** - count number of elements in cpu_data. Then see how
// many rows and columns we have in draw_loc (-2 on both sides for border?). // many rows and columns we have in draw_loc (-2 on both sides for border?).
// I think what we can do is try to fit in as many in one column as possible. // I think what we can do is try to fit in as many in one column as possible.
// If not, then add a new column. // If not, then add a new column.
// Then, from this, split the row space across ALL columns. From there, generate // Then, from this, split the row space across ALL columns. From there, generate
// the desired lengths. // the desired lengths.
if app_state.current_widget.widget_id == widget_id { if app_state.current_widget.widget_id == widget_id {
f.render_widget( f.render_widget(
Block::default() Block::default()
.borders(*SIDE_BORDERS) .borders(*SIDE_BORDERS)
.border_style(self.colours.highlighted_border_style), .border_style(self.colours.highlighted_border_style),
draw_loc, draw_loc,
); );
} }
let num_cpus = cpu_data.len(); let num_cpus = cpu_data.len();
if draw_loc.height > 0 {
let remaining_height = usize::from(draw_loc.height);
const REQUIRED_COLUMNS: usize = 4;
let chunk_vec = if draw_loc.height > 0 {
vec![Constraint::Percentage((100 / REQUIRED_COLUMNS) as u16); REQUIRED_COLUMNS]; let remaining_height = usize::from(draw_loc.height);
let chunks = Layout::default() const REQUIRED_COLUMNS: usize = 4;
.constraints(chunk_vec)
.direction(Direction::Horizontal)
.split(draw_loc);
// +9 due to 3 + 4 + 2 columns for the name & space + percentage + bar bounds let chunk_vec =
const MARGIN_SPACE: usize = 2; vec![Constraint::Percentage((100 / REQUIRED_COLUMNS) as u16); REQUIRED_COLUMNS];
let remaining_width = usize::from(draw_loc.width) let chunks = Layout::default()
.saturating_sub((9 + MARGIN_SPACE) * REQUIRED_COLUMNS - MARGIN_SPACE); .constraints(chunk_vec)
.direction(Direction::Horizontal)
.split(draw_loc);
let bar_length = remaining_width / REQUIRED_COLUMNS; // +9 due to 3 + 4 + 2 columns for the name & space + percentage + bar bounds
const MARGIN_SPACE: usize = 2;
let remaining_width = usize::from(draw_loc.width)
.saturating_sub((9 + MARGIN_SPACE) * REQUIRED_COLUMNS - MARGIN_SPACE);
// CPU (and RAM) percent bars are, uh, "heavily" inspired from htop. let bar_length = remaining_width / REQUIRED_COLUMNS;
let cpu_bars = (0..num_cpus)
.map(|cpu_index| {
let use_percentage =
if let Some(cpu_usage) = cpu_data[cpu_index].cpu_data.last() {
cpu_usage.1
} else {
0.0
};
let num_bars = calculate_basic_use_bars(use_percentage, bar_length); // CPU (and RAM) percent bars are, uh, "heavily" inspired from htop.
format!( let cpu_bars = (0..num_cpus)
"{:3}[{}{}{:3.0}%]", .map(|cpu_index| {
if app_state.app_config_fields.show_average_cpu { let use_percentage =
if cpu_index == 0 { if let Some(cpu_usage) = cpu_data[cpu_index].cpu_data.last() {
"AVG".to_string() cpu_usage.1
} else { } else {
(cpu_index - 1).to_string() 0.0
} };
} else {
cpu_index.to_string()
},
"|".repeat(num_bars),
" ".repeat(bar_length - num_bars),
use_percentage.round(),
)
})
.collect::<Vec<_>>();
let mut row_counter = num_cpus; let num_bars = calculate_basic_use_bars(use_percentage, bar_length);
let mut start_index = 0; format!(
for (itx, chunk) in chunks.iter().enumerate() { "{:3}[{}{}{:3.0}%]",
// Explicitly check... don't want an accidental DBZ or underflow if app_state.app_config_fields.show_average_cpu {
if REQUIRED_COLUMNS > itx { if cpu_index == 0 {
let to_divide = REQUIRED_COLUMNS - itx; "AVG".to_string()
let how_many_cpus = min( } else {
remaining_height, (cpu_index - 1).to_string()
(row_counter / to_divide) }
+ (if row_counter % to_divide == 0 { 0 } else { 1 }), } else {
); cpu_index.to_string()
row_counter -= how_many_cpus; },
let end_index = min(start_index + how_many_cpus, num_cpus); "|".repeat(num_bars),
let cpu_column = (start_index..end_index) " ".repeat(bar_length - num_bars),
.map(|cpu_index| { use_percentage.round(),
Spans::from(Span { )
content: (&cpu_bars[cpu_index]).into(), })
style: self.colours.cpu_colour_styles .collect::<Vec<_>>();
[cpu_index % self.colours.cpu_colour_styles.len()],
let mut row_counter = num_cpus;
let mut start_index = 0;
for (itx, chunk) in chunks.iter().enumerate() {
// Explicitly check... don't want an accidental DBZ or underflow
if REQUIRED_COLUMNS > itx {
let to_divide = REQUIRED_COLUMNS - itx;
let how_many_cpus = min(
remaining_height,
(row_counter / to_divide)
+ (if row_counter % to_divide == 0 { 0 } else { 1 }),
);
row_counter -= how_many_cpus;
let end_index = min(start_index + how_many_cpus, num_cpus);
let cpu_column = (start_index..end_index)
.map(|cpu_index| {
Spans::from(Span {
content: (&cpu_bars[cpu_index]).into(),
style: self.colours.cpu_colour_styles
[cpu_index % self.colours.cpu_colour_styles.len()],
})
}) })
}) .collect::<Vec<_>>();
.collect::<Vec<_>>();
start_index += how_many_cpus; start_index += how_many_cpus;
let margined_loc = Layout::default() let margined_loc = Layout::default()
.direction(Direction::Horizontal) .direction(Direction::Horizontal)
.constraints([Constraint::Percentage(100)]) .constraints([Constraint::Percentage(100)])
.horizontal_margin(1) .horizontal_margin(1)
.split(*chunk)[0]; .split(*chunk)[0];
f.render_widget( f.render_widget(
Paragraph::new(cpu_column).block(Block::default()), Paragraph::new(cpu_column).block(Block::default()),
margined_loc, margined_loc,
); );
}
} }
} }
} }