app.rs 1.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556
  1. use crate::dmc;
  2. use anyhow::{anyhow, bail, Result};
  3. /// The data necessary to represent a stich legend icon.
  4. pub struct Data {
  5. /// The character we want to draw.
  6. pub symbol: char,
  7. /// The DMC thread color we want to use. This will be `None` if
  8. /// the user has not entered in a valid DMC thread, and we'll draw
  9. /// a bland gray background in that case
  10. pub dmc: Option<dmc::DMC>,
  11. }
  12. impl Data {
  13. pub fn draw_to_file<P: AsRef<std::path::Path>>(&self, path: P) -> Result<()> {
  14. let f = std::fs::File::create(path)?;
  15. let surf = cairo::SvgSurface::for_stream(100.0, 100.0, f)?;
  16. self.render(&cairo::Context::new(&surf), 100.0, 100.0)?;
  17. if let Err(err) = surf.finish_output_stream() {
  18. bail!(err.error);
  19. };
  20. Ok(())
  21. }
  22. pub fn render(&self, ctx: &cairo::Context, w: f64, h: f64) -> Result<()> {
  23. let off_x = (w - 100.) / 2.0;
  24. let off_y = (h - 100.) / 2.0;
  25. let color = self.color();
  26. ctx.set_source_rgb(color.0, color.1, color.2);
  27. ctx.paint();
  28. ctx.set_source_rgb(0., 0., 0.);
  29. ctx.rectangle(off_x, off_y, 100., 100.);
  30. ctx.stroke();
  31. ctx.move_to(off_x, off_y - 23.0);
  32. let layout = pangocairo::functions::create_layout(&ctx)
  33. .ok_or_else(|| anyhow!("Could not create layout"))?;
  34. layout.set_width(100 * 1024);
  35. layout.set_alignment(pango::Alignment::Center);
  36. let font = pango::FontDescription::from_string("Fira Sans 92");
  37. layout.set_font_description(Some(&font));
  38. layout.set_text(&self.symbol.to_string());
  39. pangocairo::functions::show_layout(&ctx, &layout);
  40. Ok(())
  41. }
  42. fn color(&self) -> (f64, f64, f64) {
  43. self.dmc
  44. .map(|dmc| dmc.color)
  45. .unwrap_or_else(|| (0.5, 0.5, 0.5))
  46. }
  47. }