use pango::LayoutExt; #[derive(Debug,Clone,Copy)] pub struct Size { pub wd: i32, pub ht: i32, pub xo: i32, pub yo: i32, } #[derive(Debug,Clone,Copy)] pub enum Located { FromLeft(i32), FromRight(i32), } impl Located { fn draw_text(&self, d: &Drawing, msg: &str) -> i32 { d.lyt.set_text(msg); let (w, _) = d.lyt.get_size(); d.ctx.move_to(self.target_x(d, w / pango::SCALE), 4.0); pangocairo::functions::show_layout(d.ctx, d.lyt); w / pango::SCALE } fn target_x(&self, d: &Drawing, w: i32) -> f64 { match self { Located::FromLeft(x) => *x as f64, Located::FromRight(x) => (d.size.wd - (x + w)) as f64, } } } pub struct Drawing<'t> { pub ctx: &'t cairo::Context, pub lyt: &'t pango::Layout, pub size: Size, pub stdin: &'t str, } pub trait Widget { fn draw(&self, d: &Drawing, loc: Located) -> i32; } #[derive(Debug)] pub struct Time { fmt: String, } impl Time { pub fn new() -> Time { Time { fmt: format!("%a %b %d %H:%M") } } } impl Widget for Time { fn draw(&self, d: &Drawing, loc: Located) -> i32 { let now = chrono::Local::now(); loc.draw_text(d, &format!("{}", &now.format(&self.fmt))) } } #[derive(Debug)] pub struct Stdin; impl Stdin { pub fn new() -> Stdin { Stdin } } impl Widget for Stdin { fn draw(&self, d: &Drawing, loc: Located) -> i32 { loc.draw_text(d, &d.stdin) } } pub struct SmallBox; impl Widget for SmallBox { fn draw(&self, d: &Drawing, loc: Located) -> i32 { let sz = d.size.ht - 8; let x = loc.target_x(d, sz); d.ctx.rectangle(x, 4.0, sz as f64, sz as f64); d.ctx.fill(); sz } } pub struct Battery { file_list: Vec, } impl Battery { pub fn new() -> Result { use std::fs; let mut batteries = Vec::new(); for entry in fs::read_dir("/sys/class/power_supply")? { let e = entry?; if e.file_name().to_string_lossy().starts_with("BAT") { let mut path = e.path(); path.push("capacity"); batteries.push(path); } } Ok(Battery { file_list: batteries, }) } fn read_status(&self) -> Result { let charges: Result, failure::Error> = self.file_list.iter().map(|path| { Ok(std::fs::read_to_string(path)?.trim().parse()?) }).collect(); let charges = charges?; let len = charges.len() as f64; let sum: i32 = charges.into_iter().sum(); Ok(sum as f64 / len / 100.0) } } impl Widget for Battery { fn draw(&self, d: &Drawing, loc: Located) -> i32 { let amt = self.read_status(); let sz = d.size.ht - 8; let x = loc.target_x(d, sz); match amt { Ok(x) if x < 0.1 => d.ctx.set_source_rgb(1.0, 0.0, 0.0), Ok(x) if x < 0.5 => d.ctx.set_source_rgb(1.0, 1.0, 0.0), Ok(_) => d.ctx.set_source_rgb(0.0, 1.0, 0.5), Err(_) => d.ctx.set_source_rgb(0.0, 0.0, 0.0), } d.ctx.rectangle( x, 8.0, sz as f64 * amt.unwrap_or(1.0), sz as f64 - 8.0, ); d.ctx.fill(); d.ctx.set_source_rgb(1.0, 1.0, 1.0); d.ctx.rectangle(x, 8.0, sz as f64, sz as f64 - 8.0); d.ctx.stroke(); sz } }