diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/app.rs | 71 | ||||
-rw-r--r-- | src/app/data_farmer.rs | 33 | ||||
-rw-r--r-- | src/app/data_harvester.rs | 2 | ||||
-rw-r--r-- | src/app/data_harvester/batteries.rs | 12 | ||||
-rw-r--r-- | src/app/data_harvester/disks.rs | 10 | ||||
-rw-r--r-- | src/app/data_harvester/network.rs | 13 | ||||
-rw-r--r-- | src/app/data_harvester/processes.rs | 26 | ||||
-rw-r--r-- | src/app/data_harvester/temperature.rs | 6 | ||||
-rw-r--r-- | src/app/query.rs | 6 | ||||
-rw-r--r-- | src/app/states.rs | 26 | ||||
-rw-r--r-- | src/bin/main.rs | 7 | ||||
-rw-r--r-- | src/canvas.rs | 4 | ||||
-rw-r--r-- | src/canvas/dialogs/dd_dialog.rs | 8 | ||||
-rw-r--r-- | src/canvas/drawing_utils.rs | 17 | ||||
-rw-r--r-- | src/canvas/widgets/cpu_graph.rs | 81 | ||||
-rw-r--r-- | src/canvas/widgets/mem_graph.rs | 106 | ||||
-rw-r--r-- | src/canvas/widgets/network_graph.rs | 577 | ||||
-rw-r--r-- | src/clap.rs | 28 | ||||
-rw-r--r-- | src/constants.rs | 6 | ||||
-rw-r--r-- | src/data_conversion.rs | 198 | ||||
-rw-r--r-- | src/lib.rs | 36 | ||||
-rw-r--r-- | src/options.rs | 71 | ||||
-rw-r--r-- | src/units.rs | 1 | ||||
-rw-r--r-- | src/units/data_units.rs | 5 | ||||
-rw-r--r-- | src/utils/error.rs | 4 | ||||
-rw-r--r-- | src/utils/gen_util.rs | 99 |
26 files changed, 1102 insertions, 351 deletions
@@ -21,6 +21,7 @@ use crate::{ options::Config, options::ConfigFlags, options::WidgetIdEnabled, + units::data_units::DataUnit, utils::error::{BottomError, Result}, Pid, }; @@ -34,6 +35,12 @@ pub mod states; const MAX_SEARCH_LENGTH: usize = 200; +#[derive(Debug, Clone)] +pub enum AxisScaling { + Log, + Linear, +} + /// AppConfigFields is meant to cover basic fields that would normally be set /// by config files or launch options. #[derive(Debug)] @@ -55,6 +62,10 @@ pub struct AppConfigFields { pub no_write: bool, pub show_table_scroll_position: bool, pub is_advanced_kill: bool, + // TODO: Remove these, move network details state-side. + pub network_unit_type: DataUnit, + pub network_scale_type: AxisScaling, + pub network_use_binary_prefix: bool, } /// For filtering out information @@ -708,7 +719,7 @@ impl App { if self.delete_dialog_state.is_showing_dd { if self.dd_err.is_some() { self.close_dd(); - } else if self.delete_dialog_state.selected_signal != KillSignal::CANCEL { + } else if self.delete_dialog_state.selected_signal != KillSignal::Cancel { // If within dd... if self.dd_err.is_none() { // Also ensure that we didn't just fail a dd... @@ -886,7 +897,7 @@ impl App { if kbd_signal > 31 { kbd_signal %= 10; } - self.delete_dialog_state.selected_signal = KillSignal::KILL(kbd_signal); + self.delete_dialog_state.selected_signal = KillSignal::Kill(kbd_signal); if kbd_signal < 10 { self.delete_dialog_state.keyboard_signal_select = kbd_signal; } else { @@ -991,15 +1002,15 @@ impl App { { if self.app_config_fields.is_advanced_kill { match self.delete_dialog_state.selected_signal { - KillSignal::KILL(prev_signal) => { + KillSignal::Kill(prev_signal) => { self.delete_dialog_state.selected_signal = match prev_signal - 1 { - 0 => KillSignal::CANCEL, + 0 => KillSignal::Cancel, // 32+33 are skipped - 33 => KillSignal::KILL(31), - signal => KillSignal::KILL(signal), + 33 => KillSignal::Kill(31), + signal => KillSignal::Kill(signal), }; } - KillSignal::CANCEL => {} + KillSignal::Cancel => {} }; } else { self.delete_dialog_state.selected_signal = KillSignal::default(); @@ -1007,7 +1018,7 @@ impl App { } #[cfg(target_os = "windows")] { - self.delete_dialog_state.selected_signal = KillSignal::KILL(1); + self.delete_dialog_state.selected_signal = KillSignal::Kill(1); } } } @@ -1067,23 +1078,23 @@ impl App { { if self.app_config_fields.is_advanced_kill { let new_signal = match self.delete_dialog_state.selected_signal { - KillSignal::CANCEL => 1, + KillSignal::Cancel => 1, // 32+33 are skipped #[cfg(target_os = "linux")] - KillSignal::KILL(31) => 34, + KillSignal::Kill(31) => 34, #[cfg(target_os = "macos")] - KillSignal::KILL(31) => 31, - KillSignal::KILL(64) => 64, - KillSignal::KILL(signal) => signal + 1, + KillSignal::Kill(31) => 31, + KillSignal::Kill(64) => 64, + KillSignal::Kill(signal) => signal + 1, }; - self.delete_dialog_state.selected_signal = KillSignal::KILL(new_signal); + self.delete_dialog_state.selected_signal = KillSignal::Kill(new_signal); } else { - self.delete_dialog_state.selected_signal = KillSignal::CANCEL; + self.delete_dialog_state.selected_signal = KillSignal::Cancel; } } #[cfg(target_os = "windows")] { - self.delete_dialog_state.selected_signal = KillSignal::CANCEL; + self.delete_dialog_state.selected_signal = KillSignal::Cancel; } } } @@ -1091,15 +1102,15 @@ impl App { pub fn on_page_up(&mut self) { if self.delete_dialog_state.is_showing_dd { let mut new_signal = match self.delete_dialog_state.selected_signal { - KillSignal::CANCEL => 0, - KillSignal::KILL(signal) => max(signal, 8) - 8, + KillSignal::Cancel => 0, + KillSignal::Kill(signal) => max(signal, 8) - 8, }; if new_signal > 23 && new_signal < 33 { new_signal -= 2; } self.delete_dialog_state.selected_signal = match new_signal { - 0 => KillSignal::CANCEL, - sig => KillSignal::KILL(sig), + 0 => KillSignal::Cancel, + sig => KillSignal::Kill(sig), }; } } @@ -1107,13 +1118,13 @@ impl App { pub fn on_page_down(&mut self) { if self.delete_dialog_state.is_showing_dd { let mut new_signal = match self.delete_dialog_state.selected_signal { - KillSignal::CANCEL => 8, - KillSignal::KILL(signal) => min(signal + 8, MAX_SIGNAL), + KillSignal::Cancel => 8, + KillSignal::Kill(signal) => min(signal + 8, MAX_SIGNAL), }; if new_signal > 31 && new_signal < 42 { new_signal += 2; } - self.delete_dialog_state.selected_signal = KillSignal::KILL(new_signal); + self.delete_dialog_state.selected_signal = KillSignal::Kill(new_signal); } } @@ -1672,8 +1683,8 @@ impl App { if let Some(current_selected_processes) = &self.to_delete_process_list { #[cfg(target_family = "unix")] let signal = match self.delete_dialog_state.selected_signal { - KillSignal::KILL(sig) => sig, - KillSignal::CANCEL => 15, // should never happen, so just TERM + KillSignal::Kill(sig) => sig, + KillSignal::Cancel => 15, // should never happen, so just TERM }; for pid in ¤t_selected_processes.1 { #[cfg(target_family = "unix")] @@ -2229,7 +2240,7 @@ impl App { } else if self.help_dialog_state.is_showing_help { self.help_dialog_state.scroll_state.current_scroll_index = 0; } else if self.delete_dialog_state.is_showing_dd { - self.delete_dialog_state.selected_signal = KillSignal::CANCEL; + self.delete_dialog_state.selected_signal = KillSignal::Cancel; } } @@ -2312,7 +2323,7 @@ impl App { .max_scroll_index .saturating_sub(1); } else if self.delete_dialog_state.is_showing_dd { - self.delete_dialog_state.selected_signal = KillSignal::KILL(MAX_SIGNAL); + self.delete_dialog_state.selected_signal = KillSignal::Kill(MAX_SIGNAL); } } @@ -2871,13 +2882,13 @@ impl App { }, ) { Some((_, _, _, _, 0)) => { - self.delete_dialog_state.selected_signal = KillSignal::CANCEL + self.delete_dialog_state.selected_signal = KillSignal::Cancel } Some((_, _, _, _, idx)) => { if *idx > 31 { - self.delete_dialog_state.selected_signal = KillSignal::KILL(*idx + 2) + self.delete_dialog_state.selected_signal = KillSignal::Kill(*idx + 2) } else { - self.delete_dialog_state.selected_signal = KillSignal::KILL(*idx) + self.delete_dialog_state.selected_signal = KillSignal::Kill(*idx) } } _ => {} diff --git a/src/app/data_farmer.rs b/src/app/data_farmer.rs index bfc7ae8d..4a2f470e 100644 --- a/src/app/data_farmer.rs +++ b/src/app/data_farmer.rs @@ -19,7 +19,7 @@ use std::{time::Instant, vec::Vec}; use crate::app::data_harvester::load_avg::LoadAvgHarvest; use crate::{ data_harvester::{batteries, cpu, disks, load_avg, mem, network, processes, temperature, Data}, - utils::gen_util::get_simple_byte_values, + utils::gen_util::get_decimal_bytes, }; use regex::Regex; @@ -57,7 +57,7 @@ pub struct DataCollection { pub load_avg_harvest: load_avg::LoadAvgHarvest, pub process_harvest: Vec<processes::ProcessHarvest>, pub disk_harvest: Vec<disks::DiskHarvest>, - pub io_harvest: disks::IOHarvest, + pub io_harvest: disks::IoHarvest, pub io_labels_and_prev: Vec<((u64, u64), (u64, u64))>, pub io_labels: Vec<(String, String)>, pub temp_harvest: Vec<temperature::TempHarvest>, @@ -77,7 +77,7 @@ impl Default for DataCollection { load_avg_harvest: load_avg::LoadAvgHarvest::default(), process_harvest: Vec::default(), disk_harvest: Vec::default(), - io_harvest: disks::IOHarvest::default(), + io_harvest: disks::IoHarvest::default(), io_labels_and_prev: Vec::default(), io_labels: Vec::default(), temp_harvest: Vec::default(), @@ -95,7 +95,7 @@ impl DataCollection { self.cpu_harvest = cpu::CpuHarvest::default(); self.process_harvest = Vec::default(); self.disk_harvest = Vec::default(); - self.io_harvest = disks::IOHarvest::default(); + self.io_harvest = disks::IoHarvest::default(); self.io_labels_and_prev = Vec::default(); self.temp_harvest = Vec::default(); self.battery_harvest = Vec::default(); @@ -205,22 +205,15 @@ impl DataCollection { } fn eat_network(&mut self, network: network::NetworkHarvest, new_entry: &mut TimedData) { - // trace!("Eating network."); - // FIXME [NETWORKING; CONFIG]: The ability to config this? - // FIXME [NETWORKING]: Support bits, support switching between decimal and binary units (move the log part to conversion and switch on the fly) // RX - new_entry.rx_data = if network.rx > 0 { - (network.rx as f64).log2() - } else { - 0.0 - }; + if network.rx > 0 { + new_entry.rx_data = network.rx as f64; + } // TX - new_entry.tx_data = if network.tx > 0 { - (network.tx as f64).log2() - } else { - 0.0 - }; + if network.tx > 0 { + new_entry.tx_data = network.tx as f64; + } // In addition copy over latest data for easy reference self.network_harvest = network; @@ -250,7 +243,7 @@ impl DataCollection { } fn eat_disks( - &mut self, disks: Vec<disks::DiskHarvest>, io: disks::IOHarvest, harvested_time: Instant, + &mut self, disks: Vec<disks::DiskHarvest>, io: disks::IoHarvest, harvested_time: Instant, ) { // trace!("Eating disks."); // TODO: [PO] To implement @@ -300,8 +293,8 @@ impl DataCollection { *io_prev = (io_r_pt, io_w_pt); if let Some(io_labels) = self.io_labels.get_mut(itx) { - let converted_read = get_simple_byte_values(r_rate, false); - let converted_write = get_simple_byte_values(w_rate, false); + let converted_read = get_decimal_bytes(r_rate); + let converted_write = get_decimal_bytes(w_rate); *io_labels = ( format!("{:.*}{}/s", 0, converted_read.0, converted_read.1), format!("{:.*}{}/s", 0, converted_write.0, converted_write.1), diff --git a/src/app/data_harvester.rs b/src/app/data_harvester.rs index 3b7a0f63..207bb23a 100644 --- a/src/app/data_harvester.rs +++ b/src/app/data_harvester.rs @@ -36,7 +36,7 @@ pub struct Data { pub network: Option<network::NetworkHarvest>, pub list_of_processes: Option<Vec<processes::ProcessHarvest>>, pub disks: Option<Vec<disks::DiskHarvest>>, - pub io: Option<disks::IOHarvest>, + pub io: Option<disks::IoHarvest>, pub list_of_batteries: Option<Vec<batteries::BatteryHarvest>>, } diff --git a/src/app/data_harvester/batteries.rs b/src/app/data_harvester/batteries.rs index 66e3c76b..98cf6ae6 100644 --- a/src/app/data_harvester/batteries.rs +++ b/src/app/data_harvester/batteries.rs @@ -20,19 +20,11 @@ pub fn refresh_batteries(manager: &Manager, batteries: &mut [Battery]) -> Vec<Ba Some(BatteryHarvest { secs_until_full: { let optional_time = battery.time_to_full(); - if let Some(time) = optional_time { - Some(f64::from(time.get::<second>()) as i64) - } else { - None - } + optional_time.map(|time| f64::from(time.get::<second>()) as i64) }, secs_until_empty: { let optional_time = battery.time_to_empty(); - if let Some(time) = optional_time { - Some(f64::from(time.get::<second>()) as i64) - } else { - None - } + optional_time.map(|time| f64::from(time.get::<second>()) as i64) }, charge_percent: f64::from(battery.state_of_charge().get::<percent>()), power_consumption_rate_watts: f64::from(battery.energy_rate().get::<watt>()), diff --git a/src/app/data_harvester/disks.rs b/src/app/data_harvester/disks.rs index 246f5b5d..ba1d2d49 100644 --- a/src/app/data_harvester/disks.rs +++ b/src/app/data_harvester/disks.rs @@ -10,21 +10,21 @@ pub struct DiskHarvest { } #[derive(Clone, Debug)] -pub struct IOData { +pub struct IoData { pub read_bytes: u64, pub write_bytes: u64, } -pub type IOHarvest = std::collections::HashMap<String, Option<IOData>>; +pub type IoHarvest = std::collections::HashMap<String, Option<IoData>>; -pub async fn get_io_usage(actually_get: bool) -> crate::utils::error::Result<Option<IOHarvest>> { +pub async fn get_io_usage(actually_get: bool) -> crate::utils::error::Result<Option<IoHarvest>> { if !actually_get { return Ok(None); } use futures::StreamExt; - let mut io_hash: std::collections::HashMap<String, Option<IOData>> = + let mut io_hash: std::collections::HashMap<String, Option<IoData>> = std::collections::HashMap::new(); let counter_stream = heim::disk::io_counters().await?; @@ -37,7 +37,7 @@ pub async fn get_io_usage(actually_get: bool) -> crate::utils::error::Result<Opt // FIXME: [MOUNT POINT] Add the filter here I guess? io_hash.insert( mount_point.to_string(), - Some(IOData { + Some(IoData { read_bytes: io.read_bytes().get::<heim::units::information::byte>(), write_bytes: io.write_bytes().get::<heim::units::information::byte>(), }), diff --git a/src/app/data_harvester/network.rs b/src/app/data_harvester/network.rs index 55d757f6..52dc8468 100644 --- a/src/app/data_harvester/network.rs +++ b/src/app/data_harvester/network.rs @@ -1,6 +1,7 @@ use std::time::Instant; #[derive(Default, Clone, Debug)] +/// All units in bits. pub struct NetworkHarvest { pub rx: u64, pub tx: u64, @@ -47,8 +48,8 @@ pub async fn get_network_data( }; if to_keep { - total_rx += network.get_total_received(); - total_tx += network.get_total_transmitted(); + total_rx += network.get_total_received() * 8; + total_tx += network.get_total_transmitted() * 8; } } @@ -106,8 +107,12 @@ pub async fn get_network_data( }; if to_keep { - total_rx += io.bytes_recv().get::<heim::units::information::byte>(); - total_tx += io.bytes_sent().get::<heim::units::information::byte>(); + // TODO: Use bytes as the default instead, perhaps? + // Since you might have to do a double conversion (bytes -> bits -> bytes) in some cases; + // but if you stick to bytes, then in the bytes, case, you do no conversion, and in the bits case, + // you only do one conversion... + total_rx += io.bytes_recv().get::<heim::units::information::bit>(); + total_tx += io.bytes_sent().get::<heim::units::information::bit>(); } } } diff --git a/src/app/data_harvester/processes.rs b/src/app/data_harvester/processes.rs index 4d7beda0..52e80c27 100644 --- a/src/app/data_harvester/processes.rs +++ b/src/app/data_harvester/processes.rs @@ -2,6 +2,9 @@ use crate::Pid; use std::path::PathBuf; use sysinfo::ProcessStatus; +#[cfg(target_os = "linux")] +use std::path::Path; + #[cfg(target_family = "unix")] use crate::utils::error; @@ -168,7 +171,7 @@ fn cpu_usage_calculation( // SC in case that the parsing will fail due to length: if val.len() <= 10 { - return Err(error::BottomError::InvalidIO(format!( + return Err(error::BottomError::InvalidIo(format!( "CPU parsing will fail due to too short of a return value; saw {} values, expected 10 values.", val.len() ))); @@ -222,8 +225,8 @@ fn get_linux_process_vsize_rss(stat: &[&str]) -> (u64, u64) { #[cfg(target_os = "linux")] /// Preferably use this only on small files. -fn read_path_contents(path: &PathBuf) -> std::io::Result<String> { - Ok(std::fs::read_to_string(path)?) +fn read_path_contents(path: &Path) -> std::io::Result<String> { + std::fs::read_to_string(path) } #[cfg(target_os = "linux")] @@ -272,9 +275,8 @@ fn get_macos_cpu_usage(pids: &[i32]) -> std::io::Result<std::collections::HashMa let output = std::process::Command::new("ps") .args(&["-o", "pid=,pcpu=", "-p"]) .arg( - pids.iter() - .map(i32::to_string) - .intersperse(",".to_string()) + // Has to look like this since otherwise, it you hit a `unstable_name_collisions` warning. + Itertools::intersperse(pids.iter().map(i32::to_string), ",".to_string()) .collect::<String>(), ) .output()?; @@ -298,7 +300,7 @@ fn get_macos_cpu_usage(pids: &[i32]) -> std::io::Result<std::collections::HashMa } #[cfg(target_os = "linux")] -fn get_uid_and_gid(path: &PathBuf) -> (Option<u32>, Option<u32>) { +fn get_uid_and_gid(path: &Path) -> (Option<u32>, Option<u32>) { // FIXME: [OPT] - can we merge our /stat and /status calls? use std::io::prelude::*; use std::io::BufReader; @@ -470,15 +472,15 @@ fn read_proc( Ok(ProcessHarvest { pid, parent_pid, - name, - command, + cpu_usage_percent, mem_usage_percent, mem_usage_bytes, - cpu_usage_percent, - total_read_bytes, - total_write_bytes, + name, + command, read_bytes_per_sec, write_bytes_per_sec, + total_read_bytes, + total_write_bytes, process_state, process_state_char, uid, diff --git a/src/app/data_harvester/temperature.rs b/src/app/data_harvester/temperature.rs index 1c818e31..3786adc7 100644 --- a/src/app/data_harvester/temperature.rs +++ b/src/app/data_harvester/temperature.rs @@ -95,11 +95,7 @@ pub async fn get_temperature_data( while let Some(sensor) = sensor_data.next().await { if let Ok(sensor) = sensor { let component_name = Some(sensor.unit().to_string()); - let component_label = if let Some(label) = sensor.label() { - Some(label.to_string()) - } else { - None - }; + let component_label = sensor.label().map(|label| label.to_string()); let name = match (component_name, component_label) { (Some(name), Some(label)) => format!("{}: {}", name, label), diff --git a/src/app/query.rs b/src/app/query.rs index 5a827aec..a783c658 100644 --- a/src/app/query.rs +++ b/src/app/query.rs @@ -188,11 +188,7 @@ impl ProcessQuery for ProcWidgetState { let initial_or = Or { lhs: And { lhs: Prefix { - or: if let Some(or) = list_of_ors.pop_front() { - Some(Box::new(or)) - } else { - None - }, + or: list_of_ors.pop_front().map(Box::new), compare_prefix: None, regex_prefix: None, }, diff --git a/src/app/states.rs b/src/app/states.rs index 39dd0222..c8af1737 100644 --- a/src/app/states.rs +++ b/src/app/states.rs @@ -42,18 +42,18 @@ pub struct AppScrollWidgetState { #[derive(PartialEq)] pub enum KillSignal { - CANCEL, - KILL(usize), + Cancel, + Kill(usize), } impl Default for KillSignal { #[cfg(target_family = "unix")] fn default() -> Self { - KillSignal::KILL(15) + KillSignal::Kill(15) } #[cfg(target_os = "windows")] fn default() -> Self { - KillSignal::KILL(1) + KillSignal::Kill(1) } } @@ -690,13 +690,29 @@ impl ProcState { pub struct NetWidgetState { pub current_display_time: u64, pub autohide_timer: Option<Instant>, + // pub draw_max_range_cache: f64, + // pub draw_labels_cache: Vec<String>, + // pub draw_time_start_cache: f64, + // TODO: Re-enable these when we move net details state-side! + // pub unit_type: DataUnitTypes, + // pub scale_type: AxisScaling, } impl NetWidgetState { - pub fn init(current_display_time: u64, autohide_timer: Option<Instant>) -> Self { + pub fn init( + current_display_time: u64, + autohide_timer: Option<Instant>, + // unit_type: DataUnitTypes, + // scale_type: AxisScaling, + ) -> Self { NetWidgetState { current_display_time, autohide_timer, + // draw_max_range_cache: 0.0, + // draw_labels_cache: vec![], + // draw_time_start_cache: 0.0, + // unit_type, + // scale_type, } } } diff --git a/src/bin/main.rs b/src/bin/main.rs index 70d02efe..e9854987 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -26,6 +26,10 @@ use crossterm::{ }; use tui::{backend::CrosstermBackend, Terminal}; +// TODO: Add a debugger tool: +// Debugger binary. This isn't implemented yet; the idea for this is to make it easier to troubleshoot bug reports +// by providing a built-in debugger to help gather relevant information to narrow down the problem. + fn main() -> Result<()> { let matches = clap::get_matches(); // let is_debug = matches.is_present("debug"); @@ -178,6 +182,9 @@ fn main() -> Result<()> { false, app.app_config_fields.use_basic_mode || app.app_config_fields.use_old_network_legend, + &app.app_config_fields.network_scale_type, + &app.app_config_fields.network_unit_type, + app.app_config_fields.network_use_binary_prefix, ); app.canvas_data.network_data_rx = network_data.rx; app.canvas_data.network_data_tx = network_data.tx; diff --git a/src/canvas.rs b/src/canvas.rs index b904e217..1916f200 100644 --- a/src/canvas.rs +++ b/src/canvas.rs @@ -9,6 +9,8 @@ use tui::{ Frame, Terminal, }; +// use ordered_float::OrderedFloat; + use canvas_colours::*; use dialogs::*; use screens::*; @@ -54,7 +56,7 @@ pub struct DisplayableData { pub mem_labels: Option<(String, String)>, pub swap_labels: Option<(String, String)>, - pub mem_data: Vec<Point>, + pub mem_data: Vec<Point>, // TODO: Switch this and all data points over to a better data structure... pub swap_data: Vec<Point>, pub load_avg_data: [f32; 3], pub cpu_data: Vec<ConvertedCpuData>, diff --git a/src/canvas/dialogs/dd_dialog.rs b/src/canvas/dialogs/dd_dialog.rs index cd9029c8..0415aa2d 100644 --- a/src/canvas/dialogs/dd_dialog.rs +++ b/src/canvas/dialogs/dd_dialog.rs @@ -72,11 +72,11 @@ impl KillDialog for Painter { ) { if cfg!(target_os = "windows") || !app_state.app_config_fields.is_advanced_kill { let (yes_button, no_button) = match app_state.delete_dialog_state.selected_signal { - KillSignal::KILL(_) => ( + KillSignal::Kill(_) => ( Span::styled("Yes", self.colours.currently_selected_text_style), Span::raw("No"), ), - KillSignal::CANCEL => ( + KillSignal::Cancel => ( Span::raw("Yes"), Span::styled("No", self.colours.currently_selected_text_style), ), @@ -249,8 +249,8 @@ impl KillDialog for Painter { .split(*button_draw_loc)[1]; let mut selected = match app_state.delete_dialog_state.selected_signal { - KillSignal::CANCEL => 0, - KillSignal::KILL(signal) => signal, + KillSignal::Cancel => 0, + KillSignal::Kill(signal) => signal, }; // 32+33 are skipped if selected > 31 { diff --git a/src/canvas/drawing_utils.rs b/src/canvas/drawing_utils.rs index 222ca852..6aee1aa7 100644 --- a/src/canvas/drawing_utils.rs +++ b/src/canvas/drawing_utils.rs @@ -117,6 +117,12 @@ pub fn get_column_widths( 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, @@ -205,3 +211,14 @@ pub fn calculate_basic_use_bars(use_percentage: f64, num_bars_available: usize) num_bars_available, ) } + +/// Interpolates between two points. Mainly used to help fill in tui-rs blanks in certain situations. +/// It is expected point_one is "further left" compared to point_two. +/// A point is two floats, in (x, y) form. x is time, y is value. +pub fn interpolate_points(point_one: &(f64, f64), point_two: &(f64, f64), time: f64) -> f64 { + let delta_x = point_two.0 - point_one.0; + let delta_y = point_two.1 - point_one.1; + let slope = delta_y / delta_x; + + (point_one.1 + (time - point_one.0) * slope).max(0.0) +} diff --git a/src/canvas/widgets/cpu_graph.rs b/src/canvas/widgets/cpu_graph.rs index 1b79482f..ff6838f2 100644 --- a/src/canvas/widgets/cpu_graph.rs +++ b/src/canvas/widgets/cpu_graph.rs @@ -4,7 +4,7 @@ use unicode_segmentation::UnicodeSegmentation; use crate::{ app::{layout_manager::WidgetDirection, App}, canvas::{ - drawing_utils::{get_column_widths, get_start_position}, + drawing_utils::{get_column_widths, get_start_position, interpolate_points}, Painter, }, constants::*, @@ -146,32 +146,34 @@ impl CpuGraphWidget for Painter { ]; let y_axis_labels = vec![ - Span::styled("0%", self.colours.graph_style), + Span::styled(" 0%", self.colours.graph_style), Span::styled("100%", self.colours.graph_style), ]; + let time_start = -(cpu_widget_state.current_display_time as f64); + let x_axis = if app_state.app_config_fields.hide_time |