gdritter repos knurling / ab5f41a
Add a widget abstraction to make drawing easier Getty Ritter 5 years ago
2 changed file(s) with 133 addition(s) and 19 deletion(s). Collapse all Expand all
1 mod widgets;
12 mod window;
23
34 use std::os::unix::io::AsRawFd;
45 use pango::LayoutExt;
56
7 use widgets::Widget;
68 use window::{Display,Event,Size,Window};
79
810 fn main() {
107109
108110 /// Do our Cairo drawing. This needs to be refactored to allow for
109111 /// more configurability in terms of what gets written!
110 fn draw(ctx: &cairo::Context, left: &str, Size { wd: width, ..}: Size) {
111 // for the current time on the right
112 let now = time::now();
113
112 fn draw(ctx: &cairo::Context, left: &str, size: Size) {
114113 // the background is... gray-ish? this'll be configurable eventually
115114 ctx.set_source_rgb(0.1, 0.1, 0.1);
116115 ctx.paint();
120119
121120 // Our pango layout handles placing and drawing text
122121 let layout = pangocairo::functions::create_layout(&ctx).unwrap();
123 // for the time, we want to align it to the right
124 layout.set_alignment(pango::Alignment::Right);
125122 // allow for the whole width of the bar, minus a small fixed amount
126 layout.set_width((width - 20) * pango::SCALE);
123 layout.set_width((size.wd - 20) * pango::SCALE);
127124 // this should also be configurable, but Fira Mono is a good font
128125 let mut font = pango::FontDescription::from_string("Fira Mono 18");
129126 font.set_weight(pango::Weight::Bold);
130127 layout.set_font_description(&font);
131 // start drawing in the top-left
132 ctx.move_to(10.0, 4.0);
133 //The text here is just the nicely-rendered current time
134 layout.set_text(&time::strftime("%a %b %d %H:%M", &now).unwrap());
135 // and draw it
136 pangocairo::functions::show_layout(&ctx, &layout);
137128
138 // We can reuse the same layout, but starting from the left
139 layout.set_alignment(pango::Alignment::Left);
140 // and now we write whatever the "current text" is...
141 layout.set_text(left);
142 // and draw that!
143 pangocairo::functions::show_layout(&ctx, &layout);
129 // set up a struct with everything that widgets need to draw
130 let drawing = widgets::Drawing {
131 ctx: ctx,
132 lyt: &layout,
133 size,
134 };
135 // set up our widgets
136 let text = widgets::Text::new(left);
137 let time = widgets::Time::new();
138 let sbox = widgets::SmallBox;
139
140 // and create a 'config' which tells us which widgets to draw from
141 // the left, and which from the right
142 let config = widgets::Config {
143 left: vec![
144 &text as &Widget,
145 ],
146 right: vec![
147 &sbox as &Widget,
148 &time as &Widget,
149 ],
150 };
151 // and draw them!
152 config.draw(&drawing);
153
144154 }
1 use crate::window::Size;
2 use pango::LayoutExt;
3
4 #[derive(Debug,Clone,Copy)]
5 pub enum Located {
6 FromLeft(i32),
7 FromRight(i32),
8 }
9
10 pub struct Config<'r> {
11 pub left: Vec<&'r Widget>,
12 pub right: Vec<&'r Widget>,
13 }
14
15 impl<'r> Config<'r> {
16 pub fn draw(&self, d: &Drawing) {
17 let mut offset = 10;
18 for w in self.left.iter() {
19 offset += 10 + w.draw(d, Located::FromLeft(offset));
20 }
21 offset = 10;
22 for w in self.right.iter() {
23 offset += 10 + w.draw(d, Located::FromRight(offset));
24 }
25 }
26 }
27
28 impl Located {
29 fn draw_text(&self, d: &Drawing, msg: &str) -> i32 {
30 d.lyt.set_text(msg);
31 let (w, _) = d.lyt.get_size();
32 d.ctx.move_to(self.target_x(d, w / pango::SCALE), 4.0);
33 pangocairo::functions::show_layout(d.ctx, d.lyt);
34 w / pango::SCALE
35 }
36
37 fn target_x(&self, d: &Drawing, w: i32) -> f64 {
38 match self {
39 Located::FromLeft(x) => *x as f64,
40 Located::FromRight(x) => (d.size.wd - (x + w)) as f64,
41 }
42 }
43 }
44
45 pub struct Drawing<'t> {
46 pub ctx: &'t cairo::Context,
47 pub lyt: &'t pango::Layout,
48 pub size: Size,
49 }
50
51 pub trait Widget {
52 fn draw(&self, d: &Drawing, loc: Located) -> i32;
53 }
54
55 #[derive(Debug)]
56 pub struct Time {
57 fmt: String,
58 }
59
60 impl Time {
61 pub fn new() -> Time {
62 Time {
63 fmt: format!("%a %b %d %H:%M")
64 }
65 }
66 }
67
68 impl Widget for Time {
69 fn draw(&self, d: &Drawing, loc: Located) -> i32 {
70 let now = time::now();
71 loc.draw_text(d, &time::strftime(&self.fmt, &now).unwrap())
72 }
73 }
74
75
76 #[derive(Debug)]
77 pub struct Text<'t> {
78 text: &'t str,
79 }
80
81 impl<'t> Text<'t> {
82 pub fn new(text: &str) -> Text {
83 Text { text }
84 }
85 }
86
87 impl<'t> Widget for Text<'t> {
88 fn draw(&self, d: &Drawing, loc: Located) -> i32 {
89 loc.draw_text(d, &self.text)
90 }
91 }
92
93
94 pub struct SmallBox;
95
96 impl Widget for SmallBox {
97 fn draw(&self, d: &Drawing, loc: Located) -> i32 {
98 let sz = d.size.ht - 8;
99 let x = loc.target_x(d, sz);
100 d.ctx.rectangle(x, 4.0, sz as f64, sz as f64);
101 d.ctx.fill();
102 sz
103 }
104 }