gdritter repos knurling / b65f32c
Factor out how widgets are organized Getty Ritter 3 years ago
6 changed file(s) with 214 addition(s) and 197 deletion(s). Collapse all Expand all
6161 let section = section
6262 .as_table()
6363 .ok_or_else(|| format_err!("invalid config"))?;
64 match section["name"]
65 .as_str()
66 .ok_or_else(|| format_err!("invalid config"))?
67 {
68 "box" => target.push(Box::new(w::SmallBox)),
69 "battery" => target.push(Box::new(w::Battery::new()?)),
70 "caesura" => target.push(Box::new(w::Caesura)),
71 "sep" => target = &mut conf.right,
72 "stdin" => target.push(Box::new(w::Stdin::new())),
73 "time" => target.push(Box::new(w::Time::new())),
74 _ => (),
64 let name = section["name"].as_str().ok_or_else(|| format_err!("invalid config"))?;
65 if name == "sep" {
66 target = &mut conf.right;
67 } else {
68 target.push(w::mk_widget(name, section)?);
7569 }
7670 }
7771
1 use crate::widgets::widget::{Widget,Drawing,Located};
2
3 pub struct Battery {
4 file_list: Vec<std::path::PathBuf>,
5 charging: Option<std::path::PathBuf>,
6 }
7
8 impl Battery {
9 pub fn new() -> Result<Battery, failure::Error> {
10 use std::fs;
11
12 let mut batteries = Vec::new();
13 for entry in fs::read_dir("/sys/class/power_supply")? {
14 let e = entry?;
15 if e.file_name().to_string_lossy().starts_with("BAT") {
16 let mut path = e.path();
17 path.push("capacity");
18 batteries.push(path);
19 }
20 }
21 let ac_path = std::path::Path::new("/sys/class/power_supply/AC/online");
22
23 Ok(Battery {
24 file_list: batteries,
25 charging: if ac_path.exists() {
26 Some(ac_path.to_path_buf())
27 } else {
28 None
29 },
30 })
31 }
32
33 fn is_charging(&self) -> Result<bool, failure::Error> {
34 if let Some(path) = &self.charging {
35 let is_connected: i32 = std::fs::read_to_string(path)?.trim().parse()?;
36 Ok(is_connected != 0)
37 } else {
38 Ok(false)
39 }
40 }
41
42 fn read_status(&self) -> Result<f64, failure::Error> {
43 let charges: Result<Vec<i32>, failure::Error> = self
44 .file_list
45 .iter()
46 .map(|path| Ok(std::fs::read_to_string(path)?.trim().parse()?))
47 .collect();
48 let charges = charges?;
49
50 let len = charges.len() as f64;
51 let sum: i32 = charges.into_iter().sum();
52 Ok(sum as f64 / len / 100.0)
53 }
54 }
55
56 impl Widget for Battery {
57 fn draw(&self, d: &Drawing, loc: Located) -> i32 {
58 let amt = self.read_status();
59 let sz = d.size.ht - (d.buffer as i32 * 2);
60 let x = loc.target_x(d, sz);
61 match amt {
62 _ if self.is_charging().unwrap_or(false) => d.ctx.set_source_rgb(0.5, 0.5, 1.0),
63 Ok(x) if x < 0.1 => d.ctx.set_source_rgb(1.0, 0.0, 0.0),
64 Ok(x) if x < 0.5 => d.ctx.set_source_rgb(1.0, 1.0, 0.0),
65 Ok(_) => d.ctx.set_source_rgb(0.0, 1.0, 0.5),
66 Err(_) => d.ctx.set_source_rgb(0.0, 0.0, 0.0),
67 }
68
69 d.ctx.rectangle(
70 x,
71 d.buffer * 2.0,
72 sz as f64 * amt.unwrap_or(1.0),
73 sz as f64 - d.buffer * 2.0,
74 );
75 d.ctx.fill();
76
77 d.ctx.set_source_rgb(1.0, 1.0, 1.0);
78 d.ctx
79 .rectangle(x, d.buffer * 2.0, sz as f64, sz as f64 - (d.buffer * 2.0));
80 d.ctx.stroke();
81
82 sz
83 }
84 }
1 pub mod battery;
2 pub mod standard;
3 pub mod widget;
4
5 pub use crate::widgets::widget::{Located,Drawing,Size,Widget};
6
7 const ALL_WIDGETS: [(&str, &dyn Fn(&toml::map::Map<String, toml::Value>) -> Result<Box<dyn Widget>, failure::Error>); 5] = [
8 ("box", &|_| Ok(Box::new(standard::Time::new()))),
9 ("battery", &|_| Ok(Box::new(battery::Battery::new()?))),
10 ("caesura", &|_| Ok(Box::new(standard::Caesura))),
11 ("stdin", &|_| Ok(Box::new(standard::Stdin::new()))),
12 ("time", &|_| Ok(Box::new(standard::Time::new()))),
13 ];
14
15 pub fn mk_widget(name: &str, section: &toml::map::Map<String, toml::Value>) -> Result<Box<dyn Widget>, failure::Error> {
16 for (n, f) in ALL_WIDGETS.iter() {
17 if n == &name {
18 return f(section);
19 }
20 }
21 Err(format_err!("No widget type named {}", name))
22 }
1 pub use crate::widgets::widget::{Located,Drawing,Size,Widget};
2
3 #[derive(Debug)]
4 pub struct Time {
5 fmt: String,
6 }
7
8 impl Time {
9 pub fn new() -> Time {
10 Time {
11 fmt: "%a %b %d %H:%M".to_string(),
12 }
13 }
14 }
15
16 impl Widget for Time {
17 fn draw(&self, d: &Drawing, loc: Located) -> i32 {
18 let now = chrono::Local::now();
19 loc.draw_text(d, &format!("{}", &now.format(&self.fmt)))
20 }
21 }
22
23 #[derive(Debug)]
24 pub struct Stdin;
25
26 impl Stdin {
27 pub fn new() -> Stdin {
28 Stdin
29 }
30 }
31
32 impl Widget for Stdin {
33 fn draw(&self, d: &Drawing, loc: Located) -> i32 {
34 loc.draw_text(d, &d.stdin)
35 }
36 }
37
38 pub struct SmallBox;
39
40 impl Widget for SmallBox {
41 fn draw(&self, d: &Drawing, loc: Located) -> i32 {
42 let sz = d.size.ht - (d.buffer as i32 * 2);
43 let x = loc.target_x(d, sz);
44 d.ctx.rectangle(x, d.buffer, sz as f64, sz as f64);
45 d.ctx.fill();
46 sz
47 }
48 }
49
50 pub struct Caesura;
51
52 impl Widget for Caesura {
53 fn draw(&self, d: &Drawing, loc: Located) -> i32 {
54 let x = loc.target_x(d, 1);
55 d.ctx.move_to(x, d.buffer);
56 d.ctx.line_to(x, d.size.ht as f64 - d.buffer);
57 d.ctx.stroke();
58 2
59 }
60 }
1 #[derive(Debug, Clone, Copy)]
2 pub struct Size {
3 pub wd: i32,
4 pub ht: i32,
5 pub xo: i32,
6 pub yo: i32,
7 }
8
9 #[derive(Debug, Clone, Copy)]
10 pub enum Located {
11 FromLeft(i32),
12 FromRight(i32),
13 }
14
15 impl Located {
16 pub fn draw_text(self, d: &Drawing, msg: &str) -> i32 {
17 use pango::LayoutExt;
18 d.lyt.set_text(msg);
19 let (w, _) = d.lyt.get_size();
20 d.ctx.move_to(self.target_x(d, w / pango::SCALE), d.buffer);
21 pangocairo::functions::show_layout(d.ctx, d.lyt);
22 w / pango::SCALE
23 }
24
25 pub fn target_x(self, d: &Drawing, w: i32) -> f64 {
26 match self {
27 Located::FromLeft(x) => x as f64,
28 Located::FromRight(x) => (d.size.wd - (x + w)) as f64,
29 }
30 }
31 }
32
33 pub struct Drawing<'t> {
34 pub ctx: &'t cairo::Context,
35 pub lyt: &'t pango::Layout,
36 pub size: Size,
37 pub stdin: &'t str,
38 pub buffer: f64,
39 }
40
41 pub trait Widget {
42 fn draw(&self, d: &Drawing, loc: Located) -> i32;
43 }
+0
-186
src/widgets.rs less more
1 use pango::LayoutExt;
2
3 #[derive(Debug, Clone, Copy)]
4 pub struct Size {
5 pub wd: i32,
6 pub ht: i32,
7 pub xo: i32,
8 pub yo: i32,
9 }
10
11 #[derive(Debug, Clone, Copy)]
12 pub enum Located {
13 FromLeft(i32),
14 FromRight(i32),
15 }
16
17 impl Located {
18 fn draw_text(self, d: &Drawing, msg: &str) -> i32 {
19 d.lyt.set_text(msg);
20 let (w, _) = d.lyt.get_size();
21 d.ctx.move_to(self.target_x(d, w / pango::SCALE), d.buffer);
22 pangocairo::functions::show_layout(d.ctx, d.lyt);
23 w / pango::SCALE
24 }
25
26 fn target_x(self, d: &Drawing, w: i32) -> f64 {
27 match self {
28 Located::FromLeft(x) => x as f64,
29 Located::FromRight(x) => (d.size.wd - (x + w)) as f64,
30 }
31 }
32 }
33
34 pub struct Drawing<'t> {
35 pub ctx: &'t cairo::Context,
36 pub lyt: &'t pango::Layout,
37 pub size: Size,
38 pub stdin: &'t str,
39 pub buffer: f64,
40 }
41
42 pub trait Widget {
43 fn draw(&self, d: &Drawing, loc: Located) -> i32;
44 }
45
46 #[derive(Debug)]
47 pub struct Time {
48 fmt: String,
49 }
50
51 impl Time {
52 pub fn new() -> Time {
53 Time {
54 fmt: "%a %b %d %H:%M".to_string(),
55 }
56 }
57 }
58
59 impl Widget for Time {
60 fn draw(&self, d: &Drawing, loc: Located) -> i32 {
61 let now = chrono::Local::now();
62 loc.draw_text(d, &format!("{}", &now.format(&self.fmt)))
63 }
64 }
65
66 #[derive(Debug)]
67 pub struct Stdin;
68
69 impl Stdin {
70 pub fn new() -> Stdin {
71 Stdin
72 }
73 }
74
75 impl Widget for Stdin {
76 fn draw(&self, d: &Drawing, loc: Located) -> i32 {
77 loc.draw_text(d, &d.stdin)
78 }
79 }
80
81 pub struct SmallBox;
82
83 impl Widget for SmallBox {
84 fn draw(&self, d: &Drawing, loc: Located) -> i32 {
85 let sz = d.size.ht - (d.buffer as i32 * 2);
86 let x = loc.target_x(d, sz);
87 d.ctx.rectangle(x, d.buffer, sz as f64, sz as f64);
88 d.ctx.fill();
89 sz
90 }
91 }
92
93 pub struct Caesura;
94
95 impl Widget for Caesura {
96 fn draw(&self, d: &Drawing, loc: Located) -> i32 {
97 let x = loc.target_x(d, 1);
98 d.ctx.move_to(x, d.buffer);
99 d.ctx.line_to(x, d.size.ht as f64 - d.buffer);
100 d.ctx.stroke();
101 2
102 }
103 }
104
105 pub struct Battery {
106 file_list: Vec<std::path::PathBuf>,
107 charging: Option<std::path::PathBuf>,
108 }
109
110 impl Battery {
111 pub fn new() -> Result<Battery, failure::Error> {
112 use std::fs;
113
114 let mut batteries = Vec::new();
115 for entry in fs::read_dir("/sys/class/power_supply")? {
116 let e = entry?;
117 if e.file_name().to_string_lossy().starts_with("BAT") {
118 let mut path = e.path();
119 path.push("capacity");
120 batteries.push(path);
121 }
122 }
123 let ac_path = std::path::Path::new("/sys/class/power_supply/AC/online");
124
125 Ok(Battery {
126 file_list: batteries,
127 charging: if ac_path.exists() {
128 Some(ac_path.to_path_buf())
129 } else {
130 None
131 },
132 })
133 }
134
135 fn is_charging(&self) -> Result<bool, failure::Error> {
136 if let Some(path) = &self.charging {
137 let is_connected: i32 = std::fs::read_to_string(path)?.trim().parse()?;
138 Ok(is_connected != 0)
139 } else {
140 Ok(false)
141 }
142 }
143
144 fn read_status(&self) -> Result<f64, failure::Error> {
145 let charges: Result<Vec<i32>, failure::Error> = self
146 .file_list
147 .iter()
148 .map(|path| Ok(std::fs::read_to_string(path)?.trim().parse()?))
149 .collect();
150 let charges = charges?;
151
152 let len = charges.len() as f64;
153 let sum: i32 = charges.into_iter().sum();
154 Ok(sum as f64 / len / 100.0)
155 }
156 }
157
158 impl Widget for Battery {
159 fn draw(&self, d: &Drawing, loc: Located) -> i32 {
160 let amt = self.read_status();
161 let sz = d.size.ht - (d.buffer as i32 * 2);
162 let x = loc.target_x(d, sz);
163 match amt {
164 _ if self.is_charging().unwrap_or(false) => d.ctx.set_source_rgb(0.5, 0.5, 1.0),
165 Ok(x) if x < 0.1 => d.ctx.set_source_rgb(1.0, 0.0, 0.0),
166 Ok(x) if x < 0.5 => d.ctx.set_source_rgb(1.0, 1.0, 0.0),
167 Ok(_) => d.ctx.set_source_rgb(0.0, 1.0, 0.5),
168 Err(_) => d.ctx.set_source_rgb(0.0, 0.0, 0.0),
169 }
170
171 d.ctx.rectangle(
172 x,
173 d.buffer * 2.0,
174 sz as f64 * amt.unwrap_or(1.0),
175 sz as f64 - d.buffer * 2.0,
176 );
177 d.ctx.fill();
178
179 d.ctx.set_source_rgb(1.0, 1.0, 1.0);
180 d.ctx
181 .rectangle(x, d.buffer * 2.0, sz as f64, sz as f64 - (d.buffer * 2.0));
182 d.ctx.stroke();
183
184 sz
185 }
186 }