--- b/src/app.rs +++ a/src/app.rs @@ -15,5 +15,6 @@ + pub temp: Option>, // @@ -60,6 +61,12 @@ None }; + let temp = if args.temp || args.everything { + Some(TempWidget::new(colorscheme, args.fahrenheit)) + } else { + None + }; + let statusbar = if args.statusbar || args.everything { Some(Statusbar::new(colorscheme, program_name)) } else { @@ -76,5 +83,6 @@ net, proc, + temp, }, } } --- b/src/args.rs +++ a/src/args.rs @@ -28,6 +28,10 @@ #[structopt(short = "P", long = "no-proc")] pub proc: bool, + /// Show Temp Widget + #[structopt(short = "T", long = "temp")] + pub temp: bool, + /// Show all widgets. #[structopt(short = "E", long = "everything")] pub everything: bool, @@ -46,5 +49,8 @@ )] pub colorscheme: Colorschemes, + /// Show temperatures in fahrenheit. + #[structopt(short = "f", long = "fahrenheit")] + pub fahrenheit: bool, /// The name of the network interface to show in the Net widget. 'all' shows all interfaces. #[structopt(short = "i", long = "interface", default_value = "all")] --- b/src/colorscheme.rs +++ a/src/colorscheme.rs @@ -50,5 +50,7 @@ proc_cursor: i64, + temp_low: i64, + temp_high: i64, } pub struct Colorscheme { @@ -70,6 +72,8 @@ pub proc_cursor: Color, } + pub temp_low: Style, + pub temp_high: Style, impl From for Colorscheme { fn from(raw: ColorschemeRaw) -> Self { @@ -101,6 +105,8 @@ proc_cursor: convert_color(raw.proc_cursor), } + temp_low: Style::default().fg(convert_color(raw.temp_low)), + temp_high: Style::default().fg(convert_color(raw.temp_high)), } } --- b/src/draw.rs +++ a/src/draw.rs @@ -28,6 +28,9 @@ if widgets.net.is_some() { count += 1; } + if widgets.temp.is_some() { + count += 1; + } count } @@ -78,6 +81,11 @@ row_idx += 1; } + if let Some(temp) = widgets.temp.as_ref() { + frame.render_widget(temp, chunks[row_idx]); + row_idx += 1; + } + if let Some(net) = widgets.net.as_ref() { frame.render_widget(net, chunks[row_idx]); row_idx += 1; --- b/src/update.rs +++ a/src/update.rs @@ -19,6 +19,10 @@ widgets_to_update.push(net); } + if let Some(temp) = widgets.temp.as_mut() { + widgets_to_update.push(temp); + } + if let Some(cpu) = widgets.cpu.as_mut() { widgets_to_update.push(cpu); } --- b/src/widgets/mod.rs +++ a/src/widgets/mod.rs @@ -7,6 +7,7 @@ mod net; mod proc; mod statusbar; +mod temp; pub use self::battery::BatteryWidget; pub use self::cpu::CpuWidget; @@ -16,3 +17,4 @@ pub use self::net::NetWidget; pub use self::proc::ProcWidget; pub use self::statusbar::Statusbar; +pub use self::temp::TempWidget; --- /dev/null +++ a/src/widgets/temp.rs @@ -0,0 +1,119 @@ +use num_rational::Ratio; +use tui::buffer::Buffer; +use tui::layout::Rect; +use tui::widgets::Widget; + +use crate::colorscheme::Colorscheme; +use crate::update::UpdatableWidget; +use crate::widgets::block; + +#[cfg(target_os = "macos")] +use sysinfo::{ComponentExt, System, SystemExt}; + +#[cfg(target_os = "linux")] +use psutil::sensors; + +pub struct TempWidget<'a> { + title: String, + update_interval: Ratio, + colorscheme: &'a Colorscheme, + + fahrenheit: bool, + temp_threshold: f64, + + temp_data: Vec<(String, f64)>, +} + +impl TempWidget<'_> { + pub fn new(colorscheme: &Colorscheme, fahrenheit: bool) -> TempWidget { + TempWidget { + title: " Temperatures ".to_string(), + update_interval: Ratio::from_integer(5), + colorscheme, + + fahrenheit, + temp_threshold: 80.0, + temp_data: Vec::new(), + } + } +} + +impl UpdatableWidget for TempWidget<'_> { + #[cfg(target_os = "linux")] + fn update(&mut self) { + self.temp_data = sensors::temperatures() + .into_iter() + .filter_map(|sensor| sensor.ok()) + .map(|sensor| { + ( + match sensor.label() { + Some(label) => format!("{}-{}", sensor.unit(), label), + None => sensor.unit().to_string(), + }, + if self.fahrenheit { + sensor.current().fahrenheit() + } else { + sensor.current().celsius() + }, + ) + }) + .filter(|data| data.1 > 0.0) + .collect() + } + + #[cfg(target_os = "macos")] + fn update(&mut self) { + self.temp_data = Vec::new(); + + let sys = System::new_all(); + let sensor_data = sys.get_components(); + + for component in sensor_data { + let num: f64 = component.get_temperature() as f64; + self.temp_data + .push((component.get_label().to_string(), num)); + } + + self.temp_data + .sort_by(|a, b| b.1.partial_cmp(&a.1).unwrap()); + } + + fn get_update_interval(&self) -> Ratio { + self.update_interval + } +} + +impl<'a> Widget for &TempWidget<'a> { + fn render(self, area: Rect, buf: &mut Buffer) { + block::new(self.colorscheme, &self.title).render(area, buf); + + if area.height < 2 { + return; + } + + let inner = Rect { + x: area.x + 1, + y: area.y + 1, + width: area.width - 2, + height: area.height - 2, + }; + + for (i, (label, data)) in self.temp_data.iter().enumerate() { + if i >= inner.height as usize { + break; + } + let y = inner.y + i as u16; + buf.set_string(inner.x, y, label, self.colorscheme.text); + buf.set_string( + inner.right() - 5, + y, + format!("{:3.0}°{}", data, if self.fahrenheit { "F" } else { "C" },), + if data < &self.temp_threshold { + self.colorscheme.temp_low + } else { + self.colorscheme.temp_high + }, + ); + } + } +}