Browse Source

Add a widget abstraction to make drawing easier

Getty Ritter 5 years ago
parent
commit
ab5f41af8e
2 changed files with 134 additions and 20 deletions
  1. 30 20
      src/main.rs
  2. 104 0
      src/widgets.rs

+ 30 - 20
src/main.rs

@@ -1,8 +1,10 @@
+mod widgets;
 mod window;
 
 use std::os::unix::io::AsRawFd;
 use pango::LayoutExt;
 
+use widgets::Widget;
 use window::{Display,Event,Size,Window};
 
 fn main() {
@@ -107,10 +109,7 @@ fn main() {
 
 /// Do our Cairo drawing. This needs to be refactored to allow for
 /// more configurability in terms of what gets written!
-fn draw(ctx: &cairo::Context, left: &str, Size { wd: width, ..}: Size) {
-    // for the current time on the right
-    let now = time::now();
-
+fn draw(ctx: &cairo::Context, left: &str, size: Size) {
     // the background is... gray-ish? this'll be configurable eventually
     ctx.set_source_rgb(0.1, 0.1, 0.1);
     ctx.paint();
@@ -120,25 +119,36 @@ fn draw(ctx: &cairo::Context, left: &str, Size { wd: width, ..}: Size) {
 
     // Our pango layout handles placing and drawing text
     let layout = pangocairo::functions::create_layout(&ctx).unwrap();
-    // for the time, we want to align it to the right
-    layout.set_alignment(pango::Alignment::Right);
     // allow for the whole width of the bar, minus a small fixed amount
-    layout.set_width((width - 20) * pango::SCALE);
+    layout.set_width((size.wd - 20) * pango::SCALE);
     // this should also be configurable, but Fira Mono is a good font
     let mut font = pango::FontDescription::from_string("Fira Mono 18");
     font.set_weight(pango::Weight::Bold);
     layout.set_font_description(&font);
-    // start drawing in the top-left
-    ctx.move_to(10.0, 4.0);
-    //The text here is just the nicely-rendered current time
-    layout.set_text(&time::strftime("%a %b %d %H:%M", &now).unwrap());
-    // and draw it
-    pangocairo::functions::show_layout(&ctx, &layout);
-
-    // We can reuse the same layout, but starting from the left
-    layout.set_alignment(pango::Alignment::Left);
-    // and now we write whatever the "current text" is...
-    layout.set_text(left);
-    // and draw that!
-    pangocairo::functions::show_layout(&ctx, &layout);
+
+    // set up a struct with everything that widgets need to draw
+    let drawing = widgets::Drawing {
+        ctx: ctx,
+        lyt: &layout,
+        size,
+    };
+    // set up our widgets
+    let text = widgets::Text::new(left);
+    let time = widgets::Time::new();
+    let sbox = widgets::SmallBox;
+
+    // and create a 'config' which tells us which widgets to draw from
+    // the left, and which from the right
+    let config = widgets::Config {
+        left: vec![
+            &text as &Widget,
+        ],
+        right: vec![
+            &sbox as &Widget,
+            &time as &Widget,
+        ],
+    };
+    // and draw them!
+    config.draw(&drawing);
+
 }

+ 104 - 0
src/widgets.rs

@@ -0,0 +1,104 @@
+use crate::window::Size;
+use pango::LayoutExt;
+
+#[derive(Debug,Clone,Copy)]
+pub enum Located {
+    FromLeft(i32),
+    FromRight(i32),
+}
+
+pub struct Config<'r> {
+    pub left: Vec<&'r Widget>,
+    pub right: Vec<&'r Widget>,
+}
+
+impl<'r> Config<'r> {
+    pub fn draw(&self, d: &Drawing) {
+        let mut offset = 10;
+        for w in self.left.iter() {
+            offset += 10 + w.draw(d, Located::FromLeft(offset));
+        }
+        offset = 10;
+        for w in self.right.iter() {
+            offset += 10 + w.draw(d, Located::FromRight(offset));
+        }
+    }
+}
+
+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 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 = time::now();
+        loc.draw_text(d, &time::strftime(&self.fmt, &now).unwrap())
+    }
+}
+
+
+#[derive(Debug)]
+pub struct Text<'t> {
+    text: &'t str,
+}
+
+impl<'t> Text<'t> {
+    pub fn new(text: &str) -> Text {
+        Text { text }
+    }
+}
+
+impl<'t> Widget for Text<'t> {
+    fn draw(&self, d: &Drawing, loc: Located) -> i32 {
+        loc.draw_text(d, &self.text)
+    }
+}
+
+
+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
+    }
+}