diff --git a/CHANGELOG.md b/CHANGELOG.md index 0de1ea0f..9435a609 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -34,9 +34,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Use custom legend-hiding to stop hiding legends for memory and network widgets. - In addition, changed to using only legends within the graph for network, as well as redesigned the legend. - The old legend style can still be used via the `--use_old_network_legend` flag or `use_old_network_legend = true` option. + The old legend style can still be used via the `--use_old_network_legend` flag or `use_old_network_legend = true` config option. - - Allow for option to hide the header gap on tables. + - Allow for option to hide the header gap on tables via `--hide_table_gap` or `hide_table_gap = true`. + + - Switch to stateful widget style for tables. + + - Switch to using tui-rs' new built in linear interpolation rather than doing it manually. ### Bug Fixes diff --git a/src/app/data_farmer.rs b/src/app/data_farmer.rs index 2d4d9273..9b5a30bb 100644 --- a/src/app/data_farmer.rs +++ b/src/app/data_farmer.rs @@ -21,18 +21,14 @@ use crate::data_harvester::{ pub type TimeOffset = f64; pub type Value = f64; -pub type JoinedDataPoints = (Value, Vec<(TimeOffset, Value)>); #[derive(Debug, Default)] pub struct TimedData { - pub rx_data: JoinedDataPoints, - pub tx_data: JoinedDataPoints, - pub cpu_data: Vec, - pub mem_data: JoinedDataPoints, - pub swap_data: JoinedDataPoints, - // Unused for now - // pub io_data : JoinedDataPoints - // pub temp_data: JoinedDataPoints, + pub rx_data: Value, + pub tx_data: Value, + pub cpu_data: Vec, + pub mem_data: Value, + pub swap_data: Value, } /// AppCollection represents the pooled data stored within the main app @@ -121,19 +117,19 @@ impl DataCollection { // Network if let Some(network) = &harvested_data.network { - self.eat_network(network, harvested_time, &mut new_entry); + self.eat_network(network, &mut new_entry); } // Memory and Swap if let Some(memory) = &harvested_data.memory { if let Some(swap) = &harvested_data.swap { - self.eat_memory_and_swap(memory, swap, harvested_time, &mut new_entry); + self.eat_memory_and_swap(memory, swap, &mut new_entry); } } // CPU if let Some(cpu) = &harvested_data.cpu { - self.eat_cpu(cpu, harvested_time, &mut new_entry); + self.eat_cpu(cpu, &mut new_entry); } // Temp @@ -164,7 +160,7 @@ impl DataCollection { } fn eat_memory_and_swap( - &mut self, memory: &mem::MemHarvest, swap: &mem::MemHarvest, harvested_time: Instant, + &mut self, memory: &mem::MemHarvest, swap: &mem::MemHarvest, new_entry: &mut TimedData, ) { // Memory @@ -172,13 +168,7 @@ impl DataCollection { 0 => 0f64, total => (memory.mem_used_in_mb as f64) / (total as f64) * 100.0, }; - let mem_joining_pts = if let Some((time, last_pt)) = self.timed_data_vec.last() { - generate_joining_points(*time, last_pt.mem_data.0, harvested_time, mem_percent) - } else { - Vec::new() - }; - let mem_pt = (mem_percent, mem_joining_pts); - new_entry.mem_data = mem_pt; + new_entry.mem_data = mem_percent; // Swap if swap.mem_total_in_mb > 0 { @@ -186,13 +176,7 @@ impl DataCollection { 0 => 0f64, total => (swap.mem_used_in_mb as f64) / (total as f64) * 100.0, }; - let swap_joining_pt = if let Some((time, last_pt)) = self.timed_data_vec.last() { - generate_joining_points(*time, last_pt.swap_data.0, harvested_time, swap_percent) - } else { - Vec::new() - }; - let swap_pt = (swap_percent, swap_joining_pt); - new_entry.swap_data = swap_pt; + new_entry.swap_data = swap_percent; } // In addition copy over latest data for easy reference @@ -201,7 +185,7 @@ impl DataCollection { } fn eat_network( - &mut self, network: &network::NetworkHarvest, harvested_time: Instant, + &mut self, network: &network::NetworkHarvest, new_entry: &mut TimedData, ) { // RX @@ -210,14 +194,7 @@ impl DataCollection { } else { 0.0 }; - - let rx_joining_pts = if let Some((time, last_pt)) = self.timed_data_vec.last() { - generate_joining_points(*time, last_pt.rx_data.0, harvested_time, logged_rx_val) - } else { - Vec::new() - }; - let rx_pt = (logged_rx_val, rx_joining_pts); - new_entry.rx_data = rx_pt; + new_entry.rx_data = logged_rx_val; // TX let logged_tx_val = if network.tx as f64 > 0.0 { @@ -225,38 +202,20 @@ impl DataCollection { } else { 0.0 }; - - let tx_joining_pts = if let Some((time, last_pt)) = self.timed_data_vec.last() { - generate_joining_points(*time, last_pt.tx_data.0, harvested_time, logged_tx_val) - } else { - Vec::new() - }; - let tx_pt = (logged_tx_val, tx_joining_pts); - new_entry.tx_data = tx_pt; + new_entry.tx_data = logged_tx_val; // In addition copy over latest data for easy reference self.network_harvest = network.clone(); } fn eat_cpu( - &mut self, cpu: &[cpu::CPUData], harvested_time: Instant, new_entry: &mut TimedData, + &mut self, cpu: &[cpu::CPUData], new_entry: &mut TimedData, ) { // Note this only pre-calculates the data points - the names will be // within the local copy of cpu_harvest. Since it's all sequential // it probably doesn't matter anyways. - if let Some((time, last_pt)) = self.timed_data_vec.last() { - for (cpu, last_pt_data) in cpu.iter().zip(&last_pt.cpu_data) { - let cpu_joining_pts = - generate_joining_points(*time, last_pt_data.0, harvested_time, cpu.cpu_usage); - let cpu_pt = (cpu.cpu_usage, cpu_joining_pts); - new_entry.cpu_data.push(cpu_pt); - } - } else { - for cpu in cpu.iter() { - let cpu_pt = (cpu.cpu_usage, Vec::new()); - new_entry.cpu_data.push(cpu_pt); - } - } + cpu.iter() + .for_each(|cpu| new_entry.cpu_data.push(cpu.cpu_usage)); self.cpu_harvest = cpu.to_vec(); } @@ -309,36 +268,3 @@ impl DataCollection { self.battery_harvest = list_of_batteries.to_vec(); } } - -pub fn generate_joining_points( - start_x: Instant, start_y: f64, end_x: Instant, end_y: f64, -) -> Vec<(TimeOffset, Value)> { - let mut points: Vec<(TimeOffset, Value)> = Vec::new(); - - // Convert time floats first: - let tmp_time_diff = (end_x).duration_since(start_x).as_millis() as f64; - let time_difference = if tmp_time_diff == 0.0 { - 0.001 - } else { - tmp_time_diff - }; - let value_difference = end_y - start_y; - - // Let's generate... about this many points! - let num_points = std::cmp::min( - std::cmp::max( - (value_difference.abs() / time_difference * 2000.0) as u64, - 50, - ), - 2000, - ); - - for itx in (0..num_points).step_by(2) { - points.push(( - time_difference - (itx as f64 / num_points as f64 * time_difference), - start_y + (itx as f64 / num_points as f64 * value_difference), - )); - } - - points -} diff --git a/src/canvas/widgets/cpu_graph.rs b/src/canvas/widgets/cpu_graph.rs index a77c100a..cefed8a2 100644 --- a/src/canvas/widgets/cpu_graph.rs +++ b/src/canvas/widgets/cpu_graph.rs @@ -146,7 +146,7 @@ impl CpuGraphWidget for Painter { .enumerate() .rev() .filter_map(|(itx, (cpu, cpu_show_vec))| { - if *cpu_show_vec { + if *cpu_show_vec && !cpu.cpu_data.is_empty() { Some( Dataset::default() .marker(if use_dot { @@ -160,7 +160,8 @@ impl CpuGraphWidget for Painter { self.colours.cpu_colour_styles [itx % self.colours.cpu_colour_styles.len()] }) - .data(&cpu.cpu_data[..]), + .data(&cpu.cpu_data[..]) + .graph_type(tui::widgets::GraphType::Line), ) } else { None diff --git a/src/canvas/widgets/mem_graph.rs b/src/canvas/widgets/mem_graph.rs index 7b70d430..a15f01bc 100644 --- a/src/canvas/widgets/mem_graph.rs +++ b/src/canvas/widgets/mem_graph.rs @@ -61,26 +61,37 @@ impl MemGraphWidget for Painter { .bounds([-0.5, 100.5]) .labels(&["0%", "100%"]); - let mem_canvas_vec: Vec> = vec![ - Dataset::default() - .name(&app_state.canvas_data.mem_label) - .marker(if app_state.app_config_fields.use_dot { - Marker::Dot - } else { - Marker::Braille - }) - .style(self.colours.ram_style) - .data(&mem_data), - Dataset::default() - .name(&app_state.canvas_data.swap_label) - .marker(if app_state.app_config_fields.use_dot { - Marker::Dot - } else { - Marker::Braille - }) - .style(self.colours.swap_style) - .data(&swap_data), - ]; + let mut mem_canvas_vec: Vec> = vec![]; + + if !mem_data.is_empty() { + mem_canvas_vec.push( + Dataset::default() + .name(&app_state.canvas_data.mem_label) + .marker(if app_state.app_config_fields.use_dot { + Marker::Dot + } else { + Marker::Braille + }) + .style(self.colours.ram_style) + .data(&mem_data) + .graph_type(tui::widgets::GraphType::Line), + ); + } + + if !swap_data.is_empty() { + mem_canvas_vec.push( + Dataset::default() + .name(&app_state.canvas_data.swap_label) + .marker(if app_state.app_config_fields.use_dot { + Marker::Dot + } else { + Marker::Braille + }) + .style(self.colours.swap_style) + .data(&swap_data) + .graph_type(tui::widgets::GraphType::Line), + ); + } let title = if app_state.is_expanded { const TITLE_BASE: &str = " Memory ── Esc to go back "; diff --git a/src/canvas/widgets/network_graph.rs b/src/canvas/widgets/network_graph.rs index 1b72251b..d2d49c90 100644 --- a/src/canvas/widgets/network_graph.rs +++ b/src/canvas/widgets/network_graph.rs @@ -132,59 +132,90 @@ impl NetworkGraphWidget for Painter { }; let dataset = if app_state.app_config_fields.use_old_network_legend && !hide_legend { - vec![ - Dataset::default() - .name(format!("RX: {:7}", app_state.canvas_data.rx_display)) - .marker(if app_state.app_config_fields.use_dot { - Marker::Dot - } else { - Marker::Braille - }) - .style(self.colours.rx_style) - .data(&network_data_rx), - Dataset::default() - .name(format!("TX: {:7}", app_state.canvas_data.tx_display)) - .marker(if app_state.app_config_fields.use_dot { - Marker::Dot - } else { - Marker::Braille - }) - .style(self.colours.tx_style) - .data(&network_data_tx), - Dataset::default() - .name(format!( - "Total RX: {:7}", - app_state.canvas_data.total_rx_display - )) - .style(self.colours.total_rx_style), + let mut ret_val = vec![]; + + if !network_data_rx.is_empty() { + ret_val.push( + Dataset::default() + .name(format!("RX: {:7}", app_state.canvas_data.rx_display)) + .marker(if app_state.app_config_fields.use_dot { + Marker::Dot + } else { + Marker::Braille + }) + .style(self.colours.rx_style) + .data(&network_data_rx) + .graph_type(tui::widgets::GraphType::Line), + ); + } + + if !network_data_tx.is_empty() { + ret_val.push( + Dataset::default() + .name(format!("TX: {:7}", app_state.canvas_data.tx_display)) + .marker(if app_state.app_config_fields.use_dot { + Marker::Dot + } else { + Marker::Braille + }) + .style(self.colours.tx_style) + .data(&network_data_tx) + .graph_type(tui::widgets::GraphType::Line), + ); + ret_val.push( + Dataset::default() + .name(format!( + "Total RX: {:7}", + app_state.canvas_data.total_rx_display + )) + .style(self.colours.total_rx_style), + ); + } + + ret_val.push( Dataset::default() .name(format!( "Total TX: {:7}", app_state.canvas_data.total_tx_display )) .style(self.colours.total_tx_style), - ] + ); + + ret_val } else { - vec![ - Dataset::default() - .name(&app_state.canvas_data.rx_display) - .marker(if app_state.app_config_fields.use_dot { - Marker::Dot - } else { - Marker::Braille - }) - .style(self.colours.rx_style) - .data(&network_data_rx), - Dataset::default() - .name(&app_state.canvas_data.tx_display) - .marker(if app_state.app_config_fields.use_dot { - Marker::Dot - } else { - Marker::Braille - }) - .style(self.colours.tx_style) - .data(&network_data_tx), - ] + let mut ret_val = vec![]; + + if !network_data_rx.is_empty() { + ret_val.push( + Dataset::default() + .name(&app_state.canvas_data.rx_display) + .marker(if app_state.app_config_fields.use_dot { + Marker::Dot + } else { + Marker::Braille + }) + .style(self.colours.rx_style) + .data(&network_data_rx) + .graph_type(tui::widgets::GraphType::Line), + ); + } + + if !network_data_tx.is_empty() { + ret_val.push( + Dataset::default() + .name(&app_state.canvas_data.tx_display) + .marker(if app_state.app_config_fields.use_dot { + Marker::Dot + } else { + Marker::Braille + }) + .style(self.colours.tx_style) + .data(&network_data_tx) + .graph_type(tui::widgets::GraphType::Line), + ); + } + + ret_val }; f.render_widget( diff --git a/src/data_conversion.rs b/src/data_conversion.rs index 76924208..259a4e74 100644 --- a/src/data_conversion.rs +++ b/src/data_conversion.rs @@ -160,15 +160,8 @@ pub fn convert_cpu_data_points( } if let Some(cpu_data) = cpu_data_vector.get_mut(itx) { - cpu_data.legend_value = format!("{:.0}%", cpu.0.round()); - - //Insert joiner points - for &(joiner_offset, joiner_val) in &cpu.1 { - let offset_time = time_from_start + joiner_offset as f64; - cpu_data.cpu_data.push((-offset_time, joiner_val)); - } - - cpu_data.cpu_data.push((-time_from_start, cpu.0)); + cpu_data.legend_value = format!("{:.0}%", cpu.round()); + cpu_data.cpu_data.push((-time_from_start, *cpu)); } } @@ -197,13 +190,7 @@ pub fn convert_mem_data_points( for (time, data) in ¤t_data.timed_data_vec { let time_from_start: f64 = (current_time.duration_since(*time).as_millis() as f64).floor(); - //Insert joiner points - for &(joiner_offset, joiner_val) in &data.mem_data.1 { - let offset_time = time_from_start + joiner_offset as f64; - result.push((-offset_time, joiner_val)); - } - - result.push((-time_from_start, data.mem_data.0)); + result.push((-time_from_start, data.mem_data)); if *time == current_time { break; @@ -229,14 +216,7 @@ pub fn convert_swap_data_points( for (time, data) in ¤t_data.timed_data_vec { let time_from_start: f64 = (current_time.duration_since(*time).as_millis() as f64).floor(); - - //Insert joiner points - for &(joiner_offset, joiner_val) in &data.swap_data.1 { - let offset_time = time_from_start + joiner_offset as f64; - result.push((-offset_time, joiner_val)); - } - - result.push((-time_from_start, data.swap_data.0)); + result.push((-time_from_start, data.swap_data)); if *time == current_time { break; @@ -300,20 +280,8 @@ pub fn get_rx_tx_data_points( for (time, data) in ¤t_data.timed_data_vec { let time_from_start: f64 = (current_time.duration_since(*time).as_millis() as f64).floor(); - - //Insert joiner points - for &(joiner_offset, joiner_val) in &data.rx_data.1 { - let offset_time = time_from_start + joiner_offset as f64; - rx.push((-offset_time, joiner_val)); - } - - for &(joiner_offset, joiner_val) in &data.tx_data.1 { - let offset_time = time_from_start + joiner_offset as f64; - tx.push((-offset_time, joiner_val)); - } - - rx.push((-time_from_start, data.rx_data.0)); - tx.push((-time_from_start, data.tx_data.0)); + rx.push((-time_from_start, data.rx_data)); + tx.push((-time_from_start, data.tx_data)); if *time == current_time { break;