use std::cell::{Ref, RefCell, RefMut};
use anyhow::Result;
use chrono::{DateTime, Local, TimeDelta};
use serde::Deserialize;
use sysinfo::{CpuRefreshKind, RefreshKind, System};
use super::{
icon_text::{IconText, IconTextSettings},
text::TextSettings,
Style, Widget, WidgetData, WidgetError, WidgetList, WidgetNew, WidgetStyled,
};
#[derive(Deserialize, Debug, Default, Clone)]
pub struct CPUSettings {
#[serde(default, flatten)]
pub default_data: WidgetData,
#[serde(default, flatten)]
pub text_settings: TextSettings,
#[serde(default, flatten)]
pub style: Style,
#[serde(default)]
pub update_rate: u32,
}
pub struct CPU {
data: RefCell<WidgetData>,
settings: CPUSettings,
is_ready: RefCell<bool>,
icon_text: RefCell<IconText>,
sys: RefCell<System>,
last_update: RefCell<DateTime<Local>>,
update_rate: TimeDelta,
}
impl CPU {
fn get_info(&self) -> usize {
let mut sys = self.sys.borrow_mut();
sys.refresh_cpu_usage();
sys.global_cpu_usage().round() as usize
}
}
impl Widget for CPU {
fn name(&self) -> WidgetList {
WidgetList::CPU
}
fn as_styled(&self) -> Option<&dyn WidgetStyled> {
Some(self)
}
fn data(&self) -> Ref<'_, WidgetData> {
self.data.borrow()
}
fn data_mut(&self) -> RefMut<'_, WidgetData> {
self.data.borrow_mut()
}
fn bind(
&mut self,
env: std::rc::Rc<crate::root::Environment>,
) -> anyhow::Result<(), WidgetError> {
self.icon_text.borrow_mut().bind(env)
}
fn env(&self) -> Option<std::rc::Rc<crate::root::Environment>> {
self.icon_text.borrow().env()
}
fn init(&self) -> Result<(), WidgetError> {
self.apply_style()?;
self.icon_text.borrow_mut().change_text("Err");
self.icon_text.borrow_mut().change_icon("");
self.icon_text.borrow().init()?;
Ok(())
}
fn prepare(&self) -> Result<(), WidgetError> {
{
let it = self.icon_text.borrow();
it.prepare()?;
let mut it_data = it.data_mut();
let mut self_data = self.data.borrow_mut();
it_data.position = self_data.position;
self_data.width = it_data.width;
self_data.height = it_data.height;
}
self.apply_style()?;
*self.is_ready.borrow_mut() = true;
Ok(())
}
fn draw(&self) -> Result<(), WidgetError> {
if self.env().is_none() {
return Err(WidgetError::DrawWithNoEnv(WidgetList::CPU));
}
self.draw_style()?;
let mut last_update = self.last_update.borrow_mut();
if Local::now() - *last_update >= self.update_rate {
let info = self.get_info();
if self.sys.borrow_mut().cpus().is_empty() {
self.icon_text.borrow_mut().change_icon("");
self.icon_text.borrow_mut().change_text("ERR");
} else {
self.icon_text
.borrow_mut()
.change_text(format!("{info}%").as_str());
}
*last_update = Local::now();
}
{
let it = self.icon_text.borrow();
let mut it_data = it.data_mut();
let mut self_data = self.data.borrow_mut();
it_data.position = self_data.position;
self_data.width = it_data.width;
self_data.height = it_data.height;
}
self.icon_text.borrow().draw()
}
}
impl WidgetNew for CPU {
type Settings = CPUSettings;
fn new(
env: Option<std::rc::Rc<crate::root::Environment>>,
settings: Self::Settings,
) -> Result<Self, WidgetError>
where
Self: Sized,
{
Ok(Self {
data: RefCell::new(settings.default_data),
is_ready: RefCell::new(false),
icon_text: RefCell::new(IconText::new(
env.clone(),
IconTextSettings {
icon_settings: settings.text_settings.clone(),
text_settings: settings.text_settings.clone(),
..IconTextSettings::default()
},
)?),
sys: RefCell::new(System::new_with_specifics(
RefreshKind::nothing().with_cpu(CpuRefreshKind::nothing().with_cpu_usage()),
)),
update_rate: TimeDelta::milliseconds(settings.update_rate as i64),
last_update: RefCell::new(
chrono::Local::now() - TimeDelta::milliseconds(settings.update_rate as i64),
),
settings,
})
}
}
impl WidgetStyled for CPU {
fn style(&self) -> &Style {
&self.settings.style
}
}