gdritter repos delve / 85aa32e
Added abstraction over Pango markup format Getty Ritter 6 years ago
2 changed file(s) with 153 addition(s) and 61 deletion(s). Collapse all Expand all
55 extern crate rrecutils;
66 extern crate rsvg;
77
8 mod markup;
9
810 use std::{fs,io};
9 use pango::LayoutExt;
1011 use rsvg::HandleExt;
1112
1213 const SCALE: i32 = 3;
128129 }
129130 }
130131
131
132
133132 fn draw_card(card: &Card) -> Result<(), failure::Error> {
134133 use CardType::*;
135134
153152 ctx.stroke();
154153
155154 ctx.set_source_rgb(0.0, 0.0, 0.0);
156 let layout = pangocairo::functions::create_layout(&ctx)
157 .ok_or(format_err!("Unable to create Pango layout"))?;
158 let mut font = pango::FontDescription::from_string("Fira Sans 12");
159 font.set_weight(pango::Weight::Bold);
160 layout.set_font_description(&font);
161155
162156 ctx.move_to(100.0, 8.0);
163 let title = match card.card_type {
157 let mut buf = markup::MarkupBuffer::new();
158
159 match card.card_type {
164160 Weapon { ref weapon_type, .. } =>
165 format!("{} (Weapon, {:?})", card.name, weapon_type),
161 buf.push(&format!("{} (Weapon, {:?})", card.name, weapon_type)),
166162 Monster { ref hp, ref melee, ref ranged, ref arcane, ref defense, .. } => {
167 let mut buf = String::new();
168 buf.push_str(&format!(
169 "{} (Beast <span font='8' font_weight='heavy'>HP</span>{}",
170 card.name,
171 hp,
172 ));
163 buf.push(&format!("{} (Beast ", card.name));
164
165 buf.markup().size(8).weight("heavy").push("HP");
166 buf.push(&format!("{}", hp));
167
173168 if let &Some(ref m) = melee {
174 buf.push_str(&format!(" <span font='8' font_weight='heavy'>M</span>{}", m));
175 }
169 buf.space();
170 buf.markup().size(8).weight("heavy").push("M");
171 buf.push(m);
172 }
173
176174 if let &Some(ref m) = ranged {
177 buf.push_str(&format!(" <span font='8' font_weight='heavy'>R</span>{}", m));
178 }
175 buf.space();
176 buf.markup().size(8).weight("heavy").push("R");
177 buf.push(m);
178 }
179
179180 if let &Some(ref m) = arcane {
180 buf.push_str(&format!(" <span font='8' font_weight='heavy'>A</span>{}", m));
181 }
181 buf.space();
182 buf.markup().size(8).weight("heavy").push("A");
183 buf.push(m);
184 }
185
182186 if let &Some(ref m) = defense {
183 buf.push_str(&format!(" <span font='8' font_weight='heavy'>D</span>{}", m));
184 }
185 buf.push_str(")");
186 buf
187 buf.space();
188 buf.markup().size(8).weight("heavy").push("D");
189 buf.push(m);
190 }
191 buf.push(")");
187192 }
188 Generic { ref kind, .. } => format!("{} ({:?})", card.name, kind),
193 Generic { ref kind, .. } =>
194 buf.push(&format!("{} ({:?})", card.name, kind)),
189195 };
190196
191 let (attrs, text, _) = pango::parse_markup(&title, '\0')?;
192 layout.set_attributes(&attrs);
193 layout.set_text(&text);
194 pangocairo::functions::show_layout(&ctx, &layout);
197 buf.show_with_font(&ctx, markup::title_font(), None)?;
195198
196199 ctx.move_to(115.0, 26.0);
197 let layout = pangocairo::functions::create_layout(&ctx)
198 .ok_or(format_err!("Unable to create Pango layout"))?;
199 layout.set_width((390 - 115) * pango::SCALE);
200 let mut font = pango::FontDescription::from_string("Fira Sans 10");
201 font.set_weight(pango::Weight::Normal);
202 layout.set_font_description(&font);
203
204 let (attrs, text, _) = {
205 let mut buf = String::new();
206 match card.card_type {
207 Weapon { ability, effect, .. } => {
208 buf.push_str("<span font_weight=\"bold\">");
209 buf.push_str(ability);
210 buf.push_str(":</span> ");
211 buf.push_str(effect);
212 },
213 Monster { action, effect, .. } => {
214 buf.push_str("<span font_weight=\"bold\">");
215 buf.push_str(action);
216 buf.push_str(":</span> ");
217 buf.push_str(effect);
218 },
219 Generic { effect, .. } => {
220 buf.push_str(effect);
221 },
222 }
223 pango::parse_markup(&buf, '\0')?
200 let mut buf = markup::MarkupBuffer::new();
201
202 match card.card_type {
203 Weapon { ability, effect, .. } => {
204 buf.markup().weight("bold").push(&format!("{}: ", ability));
205 buf.push(effect);
206 },
207 Monster { action, effect, .. } => {
208 buf.markup().weight("bold").push(&format!("{}: ", action));
209 buf.push(effect);
210 },
211 Generic { effect, .. } => {
212 buf.push(effect);
213 },
224214 };
225215
226 layout.set_attributes(&attrs);
227 layout.set_text(&text);
228 pangocairo::functions::show_layout(&ctx, &layout);
216 buf.show_with_font(&ctx, markup::body_font(), Some(390 - 115))?;
229217
230218 let icon = rsvg::Handle::new_from_file(&card.icon)
231219 .map_err(|_| format_err!("Error loading image: {}", card.icon))?;
1 use cairo;
2 use pango;
3 use pangocairo;
4 use failure;
5
6 use pango::LayoutExt;
7
8 pub struct MarkupBuffer {
9 buf: String,
10 }
11
12 pub fn title_font() -> pango::FontDescription {
13 let mut f = pango::FontDescription::from_string("Fira Sans 12");
14 f.set_weight(pango::Weight::Bold);
15 f
16 }
17
18 pub fn body_font() -> pango::FontDescription {
19 pango::FontDescription::from_string("Fira Sans 10")
20 }
21
22 impl MarkupBuffer {
23 pub fn new() -> MarkupBuffer {
24 MarkupBuffer { buf: String::new() }
25 }
26
27 pub fn markup<'a>(&'a mut self) -> Markup<'a> {
28 Markup {
29 view: self,
30 frags: Vec::new(),
31 }
32 }
33
34 pub fn push(&mut self, s: &str) {
35 self.buf.push_str(s);
36 }
37
38 pub fn space(&mut self) {
39 self.buf.push_str(" ");
40 }
41
42 pub fn get(self) -> String {
43 self.buf
44 }
45
46 pub fn show_with_font(
47 self,
48 ctx: &cairo::Context,
49 font: pango::FontDescription,
50 width: Option<i32>,
51 ) -> Result<(), failure::Error> {
52 let layout = pangocairo::functions::create_layout(ctx)
53 .ok_or(format_err!("Unable to create Pango layout"))?;
54 layout.set_font_description(Some(&font));
55 if let Some(w) = width {
56 layout.set_width(w * pango::SCALE);
57 }
58 let content = self.get();
59 let (attrs, text, _) = pango::parse_markup(&content, '\0')?;
60 layout.set_attributes(&attrs);
61 layout.set_text(&text);
62 pangocairo::functions::show_layout(ctx, &layout);
63 Ok(())
64 }
65 }
66
67 enum Frag {
68 Weight(String),
69 Size(u8),
70 }
71
72 pub struct Markup<'a> {
73 view: &'a mut MarkupBuffer,
74 frags: Vec<Frag>,
75 }
76
77 impl<'a> Markup<'a> {
78 pub fn weight(self, s: &str) -> Markup<'a> {
79 let Markup { view, mut frags } = self;
80 frags.push(Frag::Weight(s.to_owned()));
81 Markup { view, frags }
82 }
83
84 pub fn size(self, s: u8) -> Markup<'a> {
85 let Markup { view, mut frags } = self;
86 frags.push(Frag::Size(s));
87 Markup { view, frags }
88 }
89
90 pub fn push(self, s: &str) {
91 self.view.push("<span ");
92 for f in self.frags.iter() {
93 match f {
94 &Frag::Size(s) =>
95 self.view.push(&format!("font='{}' ", s)),
96 &Frag::Weight(ref s) =>
97 self.view.push(&format!("font_weight='{}' ", s)),
98 }
99 }
100 self.view.push(">");
101 self.view.push(s);
102 self.view.push("</span>");
103 }
104 }