diff options
Diffstat (limited to 'src/app/widgets/cpu_graph.rs')
-rw-r--r-- | src/app/widgets/cpu_graph.rs | 175 |
1 files changed, 175 insertions, 0 deletions
diff --git a/src/app/widgets/cpu_graph.rs b/src/app/widgets/cpu_graph.rs new file mode 100644 index 00000000..4c127bb4 --- /dev/null +++ b/src/app/widgets/cpu_graph.rs @@ -0,0 +1,175 @@ +use std::{borrow::Cow, time::Instant}; + +use concat_string::concat_string; + +use tui::{style::Style, text::Text, widgets::Row}; + +use crate::{ + app::{data_harvester::cpu::CpuDataType, AppConfigFields}, + canvas::{canvas_colours::CanvasColours, Painter}, + components::data_table::{ + Column, ColumnHeader, DataTable, DataTableColumn, DataTableProps, DataTableStyling, + DataToCell, + }, + data_conversion::CpuWidgetData, + utils::gen_util::truncate_text, +}; + +#[derive(Default)] +pub struct CpuWidgetStyling { + pub all: Style, + pub avg: Style, + pub entries: Vec<Style>, +} + +impl CpuWidgetStyling { + fn from_colours(colours: &CanvasColours) -> Self { + let entries = if colours.cpu_colour_styles.is_empty() { + vec![Style::default()] + } else { + colours.cpu_colour_styles.clone() + }; + + Self { + all: colours.all_colour_style, + avg: colours.avg_colour_style, + entries, + } + } +} + +pub enum CpuWidgetColumn { + CPU, + Use, +} + +impl ColumnHeader for CpuWidgetColumn { + fn text(&self) -> Cow<'static, str> { + match self { + CpuWidgetColumn::CPU => "CPU".into(), + CpuWidgetColumn::Use => "Use%".into(), + } + } +} + +impl DataToCell<CpuWidgetColumn> for CpuWidgetData { + fn to_cell<'a>(&'a self, column: &CpuWidgetColumn, calculated_width: u16) -> Option<Text<'a>> { + const CPU_HIDE_BREAKPOINT: u16 = 5; + + // This is a bit of a hack, but apparently we can avoid having to do any fancy checks + // of showing the "All" on a specific column if the other is hidden by just always + // showing it on the CPU (first) column - if there isn't room for it, it will just collapse + // down. + // + // This is the same for the use percentages - we just *always* show them, and *always* hide the CPU column if + // it is too small. + match &self { + CpuWidgetData::All => match column { + CpuWidgetColumn::CPU => Some(truncate_text("All", calculated_width)), + CpuWidgetColumn::Use => None, + }, + CpuWidgetData::Entry { + data_type, + data: _, + last_entry, + } => match column { + CpuWidgetColumn::CPU => { + if calculated_width == 0 { + None + } else { + match data_type { + CpuDataType::Avg => Some(truncate_text("AVG", calculated_width)), + CpuDataType::Cpu(index) => { + let index_str = index.to_string(); + let text = if calculated_width < CPU_HIDE_BREAKPOINT { + truncate_text(&index_str, calculated_width) + } else { + truncate_text( + &concat_string!("CPU", index_str), + calculated_width, + ) + }; + + Some(text) + } + } + } + } + CpuWidgetColumn::Use => Some(truncate_text( + &format!("{:.0}%", last_entry.round()), + calculated_width, + )), + }, + } + } + + #[inline(always)] + fn style_row<'a>(&self, row: Row<'a>, painter: &Painter) -> Row<'a> { + let style = match self { + CpuWidgetData::All => painter.colours.all_colour_style, + CpuWidgetData::Entry { + data_type, + data: _, + last_entry: _, + } => match data_type { + CpuDataType::Avg => painter.colours.avg_colour_style, + CpuDataType::Cpu(index) => { + painter.colours.cpu_colour_styles + [index % painter.colours.cpu_colour_styles.len()] + } + }, + }; + + row.style(style) + } + + fn column_widths<C: DataTableColumn<CpuWidgetColumn>>( + _data: &[Self], _columns: &[C], + ) -> Vec<u16> + where + Self: Sized, + { + vec![1, 3] + } +} + +pub struct CpuWidgetState { + pub current_display_time: u64, + pub is_legend_hidden: bool, + pub show_avg: bool, + pub autohide_timer: Option<Instant>, + pub table: DataTable<CpuWidgetData, CpuWidgetColumn>, + pub styling: CpuWidgetStyling, +} + +impl CpuWidgetState { + pub fn new( + config: &AppConfigFields, current_display_time: u64, autohide_timer: Option<Instant>, + colours: &CanvasColours, + ) -> Self { + const COLUMNS: [Column<CpuWidgetColumn>; 2] = [ + Column::soft(CpuWidgetColumn::CPU, Some(0.5)), + Column::soft(CpuWidgetColumn::Use, Some(0.5)), + ]; + + let props = DataTableProps { + title: None, + table_gap: config.table_gap, + left_to_right: false, + is_basic: false, + show_table_scroll_position: false, // TODO: Should this be possible? + show_current_entry_when_unfocused: true, + }; + + let styling = DataTableStyling::from_colours(colours); + + CpuWidgetState { + current_display_time, + is_legend_hidden: false, + show_avg: config.show_average_cpu, + autohide_timer, + table: DataTable::new(COLUMNS, props, styling), + styling: CpuWidgetStyling::from_colours(colours), + } + } +} |