From 908580b7a3665b56659440ab30aa34c850db4af7 Mon Sep 17 00:00:00 2001 From: Jerzy Wilczek Date: Fri, 6 Oct 2023 01:13:40 +0200 Subject: [PATCH] Implement all of theming, in a better way. --- src/app.rs | 7 +- src/config.rs | 39 ++++-- src/config/color.rs | 42 +++--- src/config/theme.rs | 287 +++++++++++++++------------------------- src/main.rs | 10 +- src/ui.rs | 25 ++-- src/ui/chart_wrapper.rs | 52 +++++--- src/ui/cpus_bars.rs | 12 +- src/ui/disks.rs | 1 + src/ui/processes.rs | 11 +- 10 files changed, 234 insertions(+), 252 deletions(-) diff --git a/src/app.rs b/src/app.rs index 91dc8c9..a43b9de 100644 --- a/src/app.rs +++ b/src/app.rs @@ -4,7 +4,7 @@ use regex::Regex; use sysinfo::{CpuExt, Pid, Process, ProcessExt, System, SystemExt}; use systemstat::{BlockDeviceStats, Platform}; -use crate::ui::processes::Column; +use crate::{config::Config, ui::processes::Column}; /// Application result type. pub type AppResult = std::result::Result>; @@ -168,6 +168,7 @@ pub struct App { /// Is the application running? pub running: bool, pub input_state: InputState, + pub config: Config, pub cpu_history: Vec>, pub mem_history: VecDeque, @@ -185,9 +186,8 @@ pub struct App { } impl App { - #[allow(clippy::new_without_default)] /// Constructs a new instance of [`App`]. - pub fn new() -> Self { + pub fn new(config: Config) -> Self { let mut system = sysinfo::System::new(); let systemstat = systemstat::System::new(); system.refresh_cpu(); @@ -224,6 +224,7 @@ impl App { Self { running: true, input_state: Default::default(), + config, cpu_history, mem_history, mem_total, diff --git a/src/config.rs b/src/config.rs index 73f98ff..85759be 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,12 +1,12 @@ mod color; mod theme; -use std::{ffi::OsString, path::PathBuf}; +use std::path::PathBuf; -use anyhow::{Context, Result}; +use anyhow::{anyhow, Context, Result}; use serde::{Deserialize, Serialize}; -pub use color::RgbColor; +pub use color::SerdeColor; pub use theme::*; #[derive(clap::Parser)] @@ -32,7 +32,7 @@ pub struct Config { impl Config { pub fn load(cli: &Cli) -> Result { - let Some(config_dir_path) = config_path(cli) else { + let Some(config_dir_path) = config_path(cli)? else { return Ok(Default::default()); }; @@ -61,7 +61,11 @@ impl Config { }); }; - let theme = Theme::load_from_file(&config_dir_path.join("themes").join(theme))?; + let theme = if theme == "default" { + Theme::default() + } else { + Theme::load_from_file(&config_dir_path.join("themes").join(format!("{theme}.toml")))? + }; Ok(Self { theme }) } @@ -69,26 +73,35 @@ impl Config { #[derive(Debug, Serialize, Deserialize, Clone, Default)] struct RawConfig { - theme: Option, + theme: Option, } pub fn sample_config() -> String { toml::to_string_pretty(&RawConfig { - theme: Some("theme name (has to correspond with a valid theme file located in /themes/.toml)".into()) - }).unwrap() + theme: Some("default".into()), + }) + .unwrap() } -pub fn config_path(cli: &Cli) -> Option { +pub fn config_path(cli: &Cli) -> Result> { if let Some(ref path) = cli.config_path { if path.exists() { - return Some(path.clone()); + return Ok(Some(path.clone())); + } else { + return Err(anyhow!( + "The config path passed in the cli option does not exist" + )); } } if let Ok(path) = std::env::var("JWTOP_CONFIG_DIR") { let path: PathBuf = path.into(); if path.exists() { - return path.into(); + return Ok(path.into()); + } else { + return Err(anyhow!( + "The config path passed in the environment variable does not exist" + )); } } @@ -98,8 +111,8 @@ pub fn config_path(cli: &Cli) -> Option { .to_path_buf(); if path.exists() { - return Some(path); + return Ok(Some(path)); } - None + Ok(None) } diff --git a/src/config/color.rs b/src/config/color.rs index ff6e1f5..2b66a7c 100644 --- a/src/config/color.rs +++ b/src/config/color.rs @@ -1,19 +1,35 @@ +use tui::style::Color; + #[derive(Debug, Clone, Copy, Default, PartialEq, Eq)] -pub struct RgbColor(pub u8, pub u8, pub u8); +pub struct SerdeColor(pub Color); + +impl std::ops::Deref for SerdeColor { + type Target = Color; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} -impl serde::Serialize for RgbColor { +impl serde::Serialize for SerdeColor { fn serialize(&self, serializer: S) -> Result where S: serde::Serializer, { - serializer.serialize_str(&format!("#{:02x}{:02x}{:02x}", self.0, self.1, self.2)) + let Color::Rgb(r, g, b) = self.0 else { + return Err(serde::ser::Error::custom( + "only rgb colors are serializable", + )); + }; + + serializer.serialize_str(&format!("#{:02x}{:02x}{:02x}", r, g, b)) } } struct RgbColorVisitor; impl<'de> serde::de::Visitor<'de> for RgbColorVisitor { - type Value = RgbColor; + type Value = SerdeColor; fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { formatter.write_str("a string containing a hex color value looking like this: #rrggbb or like this: #RRGGBB") @@ -60,11 +76,11 @@ impl<'de> serde::de::Visitor<'de> for RgbColorVisitor { let g = color([v[2], v[3]])?; let b = color([v[4], v[5]])?; - Ok(RgbColor(r, g, b)) + Ok(SerdeColor(Color::Rgb(r, g, b))) } } -impl<'de> serde::Deserialize<'de> for RgbColor { +impl<'de> serde::Deserialize<'de> for SerdeColor { fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de>, @@ -73,32 +89,26 @@ impl<'de> serde::Deserialize<'de> for RgbColor { } } -impl From for tui::style::Color { - fn from(value: RgbColor) -> Self { - tui::style::Color::Rgb(value.0, value.1, value.2) - } -} - #[cfg(test)] mod tests { use super::*; #[derive(Debug, serde::Deserialize, serde::Serialize, PartialEq, Eq)] struct Wrapper { - color: RgbColor, + color: SerdeColor, } #[test] fn color_de() { assert_eq!( Wrapper { - color: RgbColor(0xaa, 0xbb, 0xcc) + color: SerdeColor(tui::style::Color::Rgb(0xaa, 0xbb, 0xcc)) }, toml::from_str("color = \"#AABBCC\"").unwrap() ); assert_eq!( Wrapper { - color: RgbColor(0xdd, 0xee, 0xff) + color: SerdeColor(tui::style::Color::Rgb(0xdd, 0xee, 0xff)) }, toml::from_str("color = \"#ddeeff\"").unwrap() ); @@ -107,7 +117,7 @@ mod tests { #[test] fn both_ways() { let val = Wrapper { - color: RgbColor(12, 240, 144), + color: SerdeColor(tui::style::Color::Rgb(12, 240, 144)), }; assert_eq!( val, diff --git a/src/config/theme.rs b/src/config/theme.rs index 5d6f9e0..1999b73 100644 --- a/src/config/theme.rs +++ b/src/config/theme.rs @@ -4,95 +4,67 @@ use anyhow::{Context, Result}; use serde::{Deserialize, Serialize}; use tui::style::Color; -use super::RgbColor; - -// TODO: actually, this is kind of stupid. Most of this can be handled by using serde attributes. +use super::SerdeColor; mod default_colors { - use crate::config::RgbColor; - - pub const RED: RgbColor = RgbColor(0xcc, 0x66, 0x66); - pub const GREEN: RgbColor = RgbColor(0xb5, 0xbd, 0x68); - - pub const YELLOW: RgbColor = RgbColor(0xf0, 0xc6, 0x74); + use crate::config::SerdeColor; - pub const BLUE: RgbColor = RgbColor(0x81, 0xa2, 0xbe); + pub fn red() -> SerdeColor { + SerdeColor(tui::style::Color::Red) + } - pub const MAGENTA: RgbColor = RgbColor(0xb2, 0x94, 0xbb); + pub fn green() -> SerdeColor { + SerdeColor(tui::style::Color::Green) + } - pub const CYAN: RgbColor = RgbColor(0x8a, 0xbe, 0xb7); + pub fn yellow() -> SerdeColor { + SerdeColor(tui::style::Color::Yellow) + } - pub const BG: RgbColor = RgbColor(0x1d, 0x1f, 0x21); -} + pub fn blue() -> SerdeColor { + SerdeColor(tui::style::Color::Blue) + } -#[derive(Debug, Serialize, Deserialize, Clone, Default)] -pub struct RawTheme { - widget: Option, - plot: Option, - bars: Option, - table: Option, -} + pub fn _magenta() -> SerdeColor { + SerdeColor(tui::style::Color::Magenta) + } -impl RawTheme { - fn sample_theme() -> Self { - Self { - widget: Some(RawWidgetTheme { - frame_color: Some(default_colors::CYAN), - title_color: Some(default_colors::CYAN), - background_color: Some(default_colors::BG), - }), - - plot: Some(RawPlotTheme { - axis_labels_color: Some(default_colors::CYAN), - plot_colors: vec![ - default_colors::BLUE, - default_colors::CYAN, - default_colors::GREEN, - default_colors::MAGENTA, - default_colors::RED, - default_colors::YELLOW, - ], - }), - - bars: Some(RawBarsTheme { - low_usage_color: Some(default_colors::GREEN), - medium_usage_color: Some(default_colors::YELLOW), - high_usage_color: Some(default_colors::RED), - }), - - table: Some(RawTableTheme { - header_color: Some(default_colors::BLUE), - row_color: Some(default_colors::BLUE), - }), - } + pub fn cyan() -> SerdeColor { + SerdeColor(tui::style::Color::Cyan) } -} -pub fn sample_theme() -> String { - toml::to_string_pretty(&RawTheme::sample_theme()).unwrap() -} + pub fn plot() -> Vec { + vec![ + SerdeColor(tui::style::Color::Blue), + SerdeColor(tui::style::Color::Cyan), + SerdeColor(tui::style::Color::Green), + SerdeColor(tui::style::Color::Magenta), + SerdeColor(tui::style::Color::Red), + SerdeColor(tui::style::Color::Yellow), + ] + } -fn tui_color(raw: Option, default: Color) -> Color { - raw.map(|c| c.into()).unwrap_or(default) + pub const RED: SerdeColor = SerdeColor(tui::style::Color::Rgb(0xcc, 0x66, 0x66)); + pub const GREEN: SerdeColor = SerdeColor(tui::style::Color::Rgb(0xb5, 0xbd, 0x68)); + pub const YELLOW: SerdeColor = SerdeColor(tui::style::Color::Rgb(0xf0, 0xc6, 0x74)); + pub const BLUE: SerdeColor = SerdeColor(tui::style::Color::Rgb(0x81, 0xa2, 0xbe)); + pub const MAGENTA: SerdeColor = SerdeColor(tui::style::Color::Rgb(0xb2, 0x94, 0xbb)); + pub const CYAN: SerdeColor = SerdeColor(tui::style::Color::Rgb(0x8a, 0xbe, 0xb7)); } -#[derive(Debug, Default, Clone)] +#[derive(Debug, Default, Clone, Serialize, Deserialize)] pub struct Theme { + #[serde(default)] pub widget: WidgetTheme, + + #[serde(default)] pub plot: PlotTheme, + + #[serde(default)] pub bars: BarsTheme, - pub table: TableTheme, -} -impl From for Theme { - fn from(value: RawTheme) -> Self { - Self { - widget: value.widget.map(|t| t.into()).unwrap_or_default(), - plot: value.plot.map(|t| t.into()).unwrap_or_default(), - bars: value.bars.map(|t| t.into()).unwrap_or_default(), - table: value.table.map(|t| t.into()).unwrap_or_default(), - } - } + #[serde(default)] + pub table: TableTheme, } impl Theme { @@ -100,156 +72,111 @@ impl Theme { let file = std::fs::read_to_string(path) .with_context(|| format!("Failed to read theme from {}", path.to_string_lossy()))?; - let raw: RawTheme = toml::from_str(&file).context("Failed to deserialize theme")?; + let theme: Theme = toml::from_str(&file).context("Failed to deserialize theme")?; - Ok(raw.into()) + Ok(theme) } -} -#[derive(Debug, Clone, Copy, Deserialize, Serialize)] -struct RawWidgetTheme { - frame_color: Option, - title_color: Option, - background_color: Option, -} + pub fn sample_theme() -> Self { + Self { + widget: WidgetTheme { + frame_color: default_colors::CYAN, + title_color: default_colors::CYAN, + }, -#[derive(Debug, Clone, Copy)] -pub struct WidgetTheme { - pub frame_color: Color, - pub title_color: Color, -} + plot: PlotTheme { + axis_labels_color: default_colors::CYAN, + plot_colors: vec![ + default_colors::BLUE, + default_colors::CYAN, + default_colors::GREEN, + default_colors::MAGENTA, + default_colors::RED, + default_colors::YELLOW, + ], + }, -impl Default for WidgetTheme { - fn default() -> Self { - Self { - frame_color: Color::Cyan, - title_color: Color::Cyan, + bars: BarsTheme { + low_usage_color: default_colors::GREEN, + medium_usage_color: default_colors::YELLOW, + high_usage_color: default_colors::RED, + }, + + table: TableTheme { + header_color: default_colors::BLUE, + row_color: default_colors::BLUE, + }, } } } -impl From for WidgetTheme { - fn from(value: RawWidgetTheme) -> Self { - let default = Self::default(); +#[derive(Debug, Clone, Copy, Serialize, Deserialize)] +pub struct WidgetTheme { + #[serde(default = "default_colors::cyan")] + pub frame_color: SerdeColor, + #[serde(default = "default_colors::cyan")] + pub title_color: SerdeColor, +} +impl Default for WidgetTheme { + fn default() -> Self { Self { - frame_color: tui_color(value.frame_color, default.frame_color), - title_color: tui_color(value.title_color, default.title_color), + frame_color: SerdeColor(Color::Cyan), + title_color: SerdeColor(Color::Cyan), } } } -#[derive(Debug, Clone, Deserialize, Serialize)] -struct RawPlotTheme { - axis_labels_color: Option, - plot_colors: Vec, -} - -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub struct PlotTheme { - pub axis_labels_color: Color, - pub plot_colors: Vec, + #[serde(default = "default_colors::cyan")] + pub axis_labels_color: SerdeColor, + #[serde(default = "default_colors::plot")] + pub plot_colors: Vec, } impl Default for PlotTheme { fn default() -> Self { Self { - axis_labels_color: Color::Cyan, - plot_colors: vec![ - Color::Blue, - Color::Cyan, - Color::Green, - Color::Magenta, - Color::Red, - Color::Yellow, - ], - } - } -} - -impl From for PlotTheme { - fn from(value: RawPlotTheme) -> Self { - let default = Self::default(); - - Self { - axis_labels_color: tui_color(value.axis_labels_color, default.axis_labels_color), - plot_colors: if !value.plot_colors.is_empty() { - value - .plot_colors - .into_iter() - .map(|c| c.into()) - .collect::>() - } else { - default.plot_colors - }, + axis_labels_color: SerdeColor(Color::Cyan), + plot_colors: default_colors::plot(), } } } -#[derive(Debug, Clone, Copy, Deserialize, Serialize)] -struct RawBarsTheme { - low_usage_color: Option, - medium_usage_color: Option, - high_usage_color: Option, -} - -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, Copy, Serialize, Deserialize)] pub struct BarsTheme { - pub low_usage_color: Color, - pub medium_usage_color: Color, - pub high_usage_color: Color, + #[serde(default = "default_colors::green")] + pub low_usage_color: SerdeColor, + #[serde(default = "default_colors::yellow")] + pub medium_usage_color: SerdeColor, + #[serde(default = "default_colors::red")] + pub high_usage_color: SerdeColor, } impl Default for BarsTheme { fn default() -> Self { Self { - low_usage_color: Color::Green, - medium_usage_color: Color::Yellow, - high_usage_color: Color::Red, - } - } -} - -impl From for BarsTheme { - fn from(value: RawBarsTheme) -> Self { - let default = Self::default(); - - Self { - low_usage_color: tui_color(value.low_usage_color, default.low_usage_color), - medium_usage_color: tui_color(value.medium_usage_color, default.medium_usage_color), - high_usage_color: tui_color(value.high_usage_color, default.high_usage_color), + low_usage_color: SerdeColor(Color::Green), + medium_usage_color: SerdeColor(Color::Yellow), + high_usage_color: SerdeColor(Color::Red), } } } -#[derive(Debug, Clone, Copy, Deserialize, Serialize)] -struct RawTableTheme { - header_color: Option, - row_color: Option, -} - -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, Copy, Serialize, Deserialize)] pub struct TableTheme { - pub header_color: Color, - pub row_color: Color, + #[serde(default = "default_colors::blue")] + pub header_color: SerdeColor, + #[serde(default = "default_colors::blue")] + pub row_color: SerdeColor, } impl Default for TableTheme { fn default() -> Self { Self { - header_color: Color::Blue, - row_color: Color::Blue, - } - } -} - -impl From for TableTheme { - fn from(value: RawTableTheme) -> Self { - let default = Self::default(); - - Self { - header_color: tui_color(value.header_color, default.header_color), - row_color: tui_color(value.row_color, default.row_color), + header_color: SerdeColor(Color::Blue), + row_color: SerdeColor(Color::Blue), } } } diff --git a/src/main.rs b/src/main.rs index b9fd8d3..3f58252 100644 --- a/src/main.rs +++ b/src/main.rs @@ -18,14 +18,18 @@ fn main() -> AppResult<()> { } if cli.dump_sample_theme { - println!("{}", jwtop::config::sample_theme()); + println!( + "{}", + toml::to_string_pretty(&jwtop::config::Theme::sample_theme()).unwrap() + ); + return Ok(()); } - // TODO: load the config and actually use it in the app. + let config = jwtop::config::Config::load(&cli)?; // Create an application. - let mut app = App::new(); + let mut app = App::new(config); // Initialize the terminal user interface. let backend = CrosstermBackend::new(io::stderr()); diff --git a/src/ui.rs b/src/ui.rs index 0fdebff..82af05c 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -16,7 +16,8 @@ pub mod processes; /// Renders the user interface widgets. pub fn render(app: &mut App, frame: &mut Frame<'_, B>) { - let style = Style::default().fg(Color::Cyan); + let block_style = Style::default().fg(*app.config.theme.widget.frame_color); + let title_style = Style::default().fg(*app.config.theme.widget.title_color); let block = Block::default() .borders(Borders::all()) .border_type(BorderType::Rounded); @@ -44,17 +45,18 @@ pub fn render(app: &mut App, frame: &mut Frame<'_, B>) { &app.cpu_history, Box::new(|percentage, i| format!("cpu{i}: {percentage:.1}%")), [0.0, 100.0], + &app.config, ) - .style(style) - .block(block.clone().title("cpu")) + .style(block_style) + .block(block.clone().title(Line::styled("cpu", title_style))) .label_suffix('%'), cpus[0], ); frame.render_widget( CpusBars::new(app) - .style(style) - .block(block.clone().title("cpu")), + .style(block_style) + .block(block.clone().title(Line::styled("cpu", title_style))), cpus[1], ); @@ -63,22 +65,25 @@ pub fn render(app: &mut App, frame: &mut Frame<'_, B>) { &[app.mem_history.clone()], Box::new(|used_mem, _| format!("used mem: {used_mem:.1}{}", app.mem_prefix.prefix())), [0.0, app.mem_total], + &app.config, ) - .style(style) - .block(block.clone().title("mem")) + .style(block_style) + .block(block.clone().title(Line::styled("mem", title_style))) .label_suffix(app.mem_prefix.prefix()), mem_and_disks[0], ); frame.render_widget( Disks::new(app) - .block(block.clone().title("disks")) - .style(style), + .block(block.clone().title(Line::styled("disks", title_style))) + .style(block_style), mem_and_disks[1], ); frame.render_widget( - Processes::new(app).block(block.title("procs")).style(style), + Processes::new(app) + .block(block.title(Line::styled("procs", title_style))) + .style(block_style), layout[2], ) } diff --git a/src/ui/chart_wrapper.rs b/src/ui/chart_wrapper.rs index d88f123..2889e5e 100644 --- a/src/ui/chart_wrapper.rs +++ b/src/ui/chart_wrapper.rs @@ -2,13 +2,16 @@ use std::collections::VecDeque; use tui::{ layout::{Alignment, Constraint}, - style::{Color, Style}, + style::Style, symbols::Marker, text::Span, widgets::{Axis, Block, Chart, Dataset, GraphType, Widget}, }; -use crate::app::HISTORY_LEN; +use crate::{ + app::HISTORY_LEN, + config::{Config, PlotTheme}, +}; pub struct ChartWrapper<'a, 'b> { data: Vec>, @@ -17,6 +20,7 @@ pub struct ChartWrapper<'a, 'b> { label_generator: Box String + 'a>, range: [f64; 2], label_suffix: Option, + theme: PlotTheme, } impl<'a, 'b> ChartWrapper<'a, 'b> { @@ -24,6 +28,7 @@ impl<'a, 'b> ChartWrapper<'a, 'b> { data: &[VecDeque], label_generator: Box String + 'a>, range: [f64; 2], + config: &Config, ) -> Self { let data = data .iter() @@ -42,6 +47,7 @@ impl<'a, 'b> ChartWrapper<'a, 'b> { label_generator, range, label_suffix: None, + theme: config.theme.plot.clone(), } } @@ -66,16 +72,7 @@ impl<'a, 'b> ChartWrapper<'a, 'b> { impl<'a, 'b> Widget for ChartWrapper<'a, 'b> { fn render(self, area: tui::layout::Rect, buf: &mut tui::buffer::Buffer) { - let colors = [ - Color::Blue, - Color::Cyan, - Color::Green, - Color::Magenta, - Color::Red, - Color::Yellow, - ] - .iter() - .cycle(); + let colors = self.theme.plot_colors.iter().cycle(); let datasets = self .data @@ -88,24 +85,41 @@ impl<'a, 'b> Widget for ChartWrapper<'a, 'b> { .graph_type(GraphType::Line) .marker(Marker::Braille) .name((self.label_generator)(data.last().unwrap().1, i)) - .style(Style::default().fg(color)) + .style(Style::default().fg(*color)) }) .collect(); let label_suffix = self.label_suffix.map(String::from).unwrap_or_default(); + let axis_label_style = Style::default().fg(*self.theme.axis_labels_color); + let mut chart = Chart::new(datasets) .x_axis(Axis::default().bounds([0.0, HISTORY_LEN as f64])) .y_axis( Axis::default() .bounds(self.range) .labels(vec![ - Span::raw(""), - Span::raw(format!("{:.0}{label_suffix}", self.range[1] / 5.0)), - Span::raw(format!("{:.0}{label_suffix}", self.range[1] * 2.0 / 5.0)), - Span::raw(format!("{:.0}{label_suffix}", self.range[1] * 3.0 / 5.0)), - Span::raw(format!("{:.0}{label_suffix}", self.range[1] * 4.0 / 5.0)), - Span::raw(format!("{:.0}{label_suffix}", self.range[1])), + Span::styled("", axis_label_style), + Span::styled( + format!("{:.0}{label_suffix}", self.range[1] / 5.0), + axis_label_style, + ), + Span::styled( + format!("{:.0}{label_suffix}", self.range[1] * 2.0 / 5.0), + axis_label_style, + ), + Span::styled( + format!("{:.0}{label_suffix}", self.range[1] * 3.0 / 5.0), + axis_label_style, + ), + Span::styled( + format!("{:.0}{label_suffix}", self.range[1] * 4.0 / 5.0), + axis_label_style, + ), + Span::styled( + format!("{:.0}{label_suffix}", self.range[1]), + axis_label_style, + ), ]) .labels_alignment(Alignment::Right), ) diff --git a/src/ui/cpus_bars.rs b/src/ui/cpus_bars.rs index 6cd80b1..fbd5147 100644 --- a/src/ui/cpus_bars.rs +++ b/src/ui/cpus_bars.rs @@ -1,15 +1,16 @@ use tui::{ layout::{Constraint, Direction, Layout}, - style::{Color, Style}, + style::Style, widgets::{Block, Borders, Gauge, Widget}, }; -use crate::app::App; +use crate::{app::App, config::BarsTheme}; pub struct CpusBars<'a> { cpus: Vec, style: Style, block: Option>, + theme: BarsTheme, } impl<'a> CpusBars<'a> { @@ -25,6 +26,7 @@ impl<'a> CpusBars<'a> { cpus, style: Default::default(), block: Default::default(), + theme: app.config.theme.bars, } } @@ -83,11 +85,11 @@ impl<'a> Widget for CpusBars<'a> { .enumerate() .for_each(|(i, (area, val))| { let color = if val < 50.0 { - Color::Green + *self.theme.low_usage_color } else if val < 80.0 { - Color::Yellow + *self.theme.medium_usage_color } else { - Color::Red + *self.theme.high_usage_color }; Gauge::default() diff --git a/src/ui/disks.rs b/src/ui/disks.rs index 7597c0b..70e3ef9 100644 --- a/src/ui/disks.rs +++ b/src/ui/disks.rs @@ -61,6 +61,7 @@ impl<'a, 'b> Disks<'a, 'b> { ) }), [0.0, max], + &app.config, ) .label_suffix('M'); diff --git a/src/ui/processes.rs b/src/ui/processes.rs index 561ddc6..fe3cd93 100644 --- a/src/ui/processes.rs +++ b/src/ui/processes.rs @@ -6,7 +6,10 @@ use tui::{ widgets::{block::Title, Block, Row, Table, Widget}, }; -use crate::app::{App, InputState, MemPrefix, ProcessInfo}; +use crate::{ + app::{App, InputState, MemPrefix, ProcessInfo}, + config::TableTheme, +}; #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum SortDirection { @@ -129,6 +132,7 @@ pub struct Processes<'b> { processes: Vec, style: Style, block: Option>, + theme: TableTheme, sorting: InputState, } @@ -139,6 +143,7 @@ impl<'b> Processes<'b> { processes: app.processes.clone(), style: Default::default(), block: Default::default(), + theme: app.config.theme.table, sorting: app.input_state.clone(), } @@ -189,7 +194,7 @@ impl<'b> Widget for Processes<'b> { .iter() .map(|c| c.extract_data_as_string(&p)), ) - .style(Style::default().fg(tui::style::Color::Blue)) + .style(Style::default().fg(*self.theme.row_color)) })) .column_spacing(1) .widths(&[Constraint::Ratio(1, 6); 6]) @@ -207,7 +212,7 @@ impl<'b> Widget for Processes<'b> { ) .style( Style::default() - .fg(tui::style::Color::Blue) + .fg(*self.theme.header_color) .add_modifier(Modifier::BOLD), ), )