widgets.rs 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. use pango::LayoutExt;
  2. #[derive(Debug,Clone,Copy)]
  3. pub struct Size {
  4. pub wd: i32,
  5. pub ht: i32,
  6. pub xo: i32,
  7. pub yo: i32,
  8. }
  9. #[derive(Debug,Clone,Copy)]
  10. pub enum Located {
  11. FromLeft(i32),
  12. FromRight(i32),
  13. }
  14. impl Located {
  15. fn draw_text(&self, d: &Drawing, msg: &str) -> i32 {
  16. d.lyt.set_text(msg);
  17. let (w, _) = d.lyt.get_size();
  18. d.ctx.move_to(self.target_x(d, w / pango::SCALE), d.buffer);
  19. pangocairo::functions::show_layout(d.ctx, d.lyt);
  20. w / pango::SCALE
  21. }
  22. fn target_x(&self, d: &Drawing, w: i32) -> f64 {
  23. match self {
  24. Located::FromLeft(x) => *x as f64,
  25. Located::FromRight(x) => (d.size.wd - (x + w)) as f64,
  26. }
  27. }
  28. }
  29. pub struct Drawing<'t> {
  30. pub ctx: &'t cairo::Context,
  31. pub lyt: &'t pango::Layout,
  32. pub size: Size,
  33. pub stdin: &'t str,
  34. pub buffer: f64,
  35. }
  36. pub trait Widget {
  37. fn draw(&self, d: &Drawing, loc: Located) -> i32;
  38. }
  39. #[derive(Debug)]
  40. pub struct Time {
  41. fmt: String,
  42. }
  43. impl Time {
  44. pub fn new() -> Time {
  45. Time {
  46. fmt: format!("%a %b %d %H:%M")
  47. }
  48. }
  49. }
  50. impl Widget for Time {
  51. fn draw(&self, d: &Drawing, loc: Located) -> i32 {
  52. let now = chrono::Local::now();
  53. loc.draw_text(d, &format!("{}", &now.format(&self.fmt)))
  54. }
  55. }
  56. #[derive(Debug)]
  57. pub struct Stdin;
  58. impl Stdin {
  59. pub fn new() -> Stdin {
  60. Stdin
  61. }
  62. }
  63. impl Widget for Stdin {
  64. fn draw(&self, d: &Drawing, loc: Located) -> i32 {
  65. loc.draw_text(d, &d.stdin)
  66. }
  67. }
  68. pub struct SmallBox;
  69. impl Widget for SmallBox {
  70. fn draw(&self, d: &Drawing, loc: Located) -> i32 {
  71. let sz = d.size.ht - (d.buffer as i32 * 2);
  72. let x = loc.target_x(d, sz);
  73. d.ctx.rectangle(x, d.buffer, sz as f64, sz as f64);
  74. d.ctx.fill();
  75. sz
  76. }
  77. }
  78. pub struct Caesura;
  79. impl Widget for Caesura {
  80. fn draw(&self, d: &Drawing, loc: Located) -> i32 {
  81. let x = loc.target_x(d, 1);
  82. d.ctx.move_to(x, d.buffer);
  83. d.ctx.line_to(x, d.size.ht as f64 - d.buffer);
  84. d.ctx.stroke();
  85. 2
  86. }
  87. }
  88. pub struct Battery {
  89. file_list: Vec<std::path::PathBuf>,
  90. charging: Option<std::path::PathBuf>
  91. }
  92. impl Battery {
  93. pub fn new() -> Result<Battery, failure::Error> {
  94. use std::fs;
  95. let mut batteries = Vec::new();
  96. for entry in fs::read_dir("/sys/class/power_supply")? {
  97. let e = entry?;
  98. if e.file_name().to_string_lossy().starts_with("BAT") {
  99. let mut path = e.path();
  100. path.push("capacity");
  101. batteries.push(path);
  102. }
  103. }
  104. let ac_path = std::path::Path::new("/sys/class/power_supply/AC/online");
  105. Ok(Battery {
  106. file_list: batteries,
  107. charging: if ac_path.exists() {
  108. Some(ac_path.to_path_buf())
  109. } else {
  110. None
  111. },
  112. })
  113. }
  114. fn is_charging(&self) -> Result<bool, failure::Error> {
  115. if let Some(path) = &self.charging {
  116. let is_connected: i32 =
  117. std::fs::read_to_string(path)?.trim().parse()?;
  118. Ok(is_connected != 0)
  119. } else {
  120. Ok(false)
  121. }
  122. }
  123. fn read_status(&self) -> Result<f64, failure::Error> {
  124. let charges: Result<Vec<i32>, failure::Error> =
  125. self.file_list.iter().map(|path| {
  126. Ok(std::fs::read_to_string(path)?.trim().parse()?)
  127. }).collect();
  128. let charges = charges?;
  129. let len = charges.len() as f64;
  130. let sum: i32 = charges.into_iter().sum();
  131. Ok(sum as f64 / len / 100.0)
  132. }
  133. }
  134. impl Widget for Battery {
  135. fn draw(&self, d: &Drawing, loc: Located) -> i32 {
  136. let amt = self.read_status();
  137. let sz = d.size.ht - (d.buffer as i32 * 2);
  138. let x = loc.target_x(d, sz);
  139. match amt {
  140. _ if self.is_charging().unwrap_or(false) =>
  141. d.ctx.set_source_rgb(0.5, 0.5, 1.0),
  142. Ok(x) if x < 0.1 =>
  143. d.ctx.set_source_rgb(1.0, 0.0, 0.0),
  144. Ok(x) if x < 0.5 =>
  145. d.ctx.set_source_rgb(1.0, 1.0, 0.0),
  146. Ok(_) =>
  147. d.ctx.set_source_rgb(0.0, 1.0, 0.5),
  148. Err(_) =>
  149. d.ctx.set_source_rgb(0.0, 0.0, 0.0),
  150. }
  151. d.ctx.rectangle(
  152. x,
  153. d.buffer * 2.0,
  154. sz as f64 * amt.unwrap_or(1.0),
  155. sz as f64 - d.buffer * 2.0,
  156. );
  157. d.ctx.fill();
  158. d.ctx.set_source_rgb(1.0, 1.0, 1.0);
  159. d.ctx.rectangle(x, d.buffer * 2.0, sz as f64, sz as f64 - (d.buffer * 2.0));
  160. d.ctx.stroke();
  161. sz
  162. }
  163. }