1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
use std::convert::Infallible;

use gtk::{pango, prelude::*};
use plotters_backend::{
    BackendColor, BackendCoord, BackendStyle, BackendTextStyle, DrawingBackend, DrawingErrorKind,
};

use crate::common;

/// Backend that draws to a [`gtk::Snapshot`].
#[derive(Debug)]
pub struct SnapshotBackend<'a> {
    snapshot: &'a gtk::Snapshot,
    layout: pango::Layout,
    size: (u32, u32),
}

impl<'a> SnapshotBackend<'a> {
    /// Creates a new drawing backend backed with [`gtk::Snapshot`] with
    /// the given width and height.
    pub fn new(snapshot: &'a gtk::Snapshot, (w, h): (u32, u32)) -> Self {
        let font_map = pangocairo::FontMap::default();
        let context = font_map.create_context();
        let layout = pango::Layout::new(&context);
        Self {
            snapshot,
            layout,
            size: (w, h),
        }
    }
}

impl<'a> DrawingBackend for SnapshotBackend<'a> {
    type ErrorType = Infallible;

    #[inline]
    fn get_size(&self) -> (u32, u32) {
        self.size
    }

    fn ensure_prepared(&mut self) -> Result<(), DrawingErrorKind<Self::ErrorType>> {
        Ok(())
    }

    fn present(&mut self) -> Result<(), DrawingErrorKind<Self::ErrorType>> {
        Ok(())
    }

    #[inline]
    fn draw_pixel(
        &mut self,
        point: BackendCoord,
        color: BackendColor,
    ) -> Result<(), DrawingErrorKind<Self::ErrorType>> {
        common::draw_pixel(self.snapshot, point, color)
    }

    #[inline]
    fn draw_line<S: BackendStyle>(
        &mut self,
        from: BackendCoord,
        to: BackendCoord,
        style: &S,
    ) -> Result<(), DrawingErrorKind<Self::ErrorType>> {
        common::draw_line(self.snapshot, from, to, style)
    }

    #[inline]
    fn draw_rect<S: BackendStyle>(
        &mut self,
        upper_left: BackendCoord,
        bottom_right: BackendCoord,
        style: &S,
        fill: bool,
    ) -> Result<(), DrawingErrorKind<Self::ErrorType>> {
        common::draw_rect(self.snapshot, upper_left, bottom_right, style, fill)
    }

    #[inline]
    fn draw_path<S: BackendStyle, I: IntoIterator<Item = BackendCoord>>(
        &mut self,
        raw_path: I,
        style: &S,
    ) -> Result<(), DrawingErrorKind<Self::ErrorType>> {
        common::draw_path(self.snapshot, raw_path, style)
    }

    #[inline]
    fn fill_polygon<S: BackendStyle, I: IntoIterator<Item = BackendCoord>>(
        &mut self,
        vert: I,
        style: &S,
    ) -> Result<(), DrawingErrorKind<Self::ErrorType>> {
        common::fill_polygon(self.snapshot, vert, style)
    }

    #[inline]
    fn draw_circle<S: BackendStyle>(
        &mut self,
        center: BackendCoord,
        radius: u32,
        style: &S,
        fill: bool,
    ) -> Result<(), DrawingErrorKind<Self::ErrorType>> {
        common::draw_circle(self.snapshot, center, radius, style, fill)
    }

    #[inline]
    fn estimate_text_size<TStyle: BackendTextStyle>(
        &self,
        text: &str,
        style: &TStyle,
    ) -> Result<(u32, u32), DrawingErrorKind<Self::ErrorType>> {
        common::estimate_text_size(&self.layout, text, style)
    }

    #[inline]
    fn draw_text<TStyle: BackendTextStyle>(
        &mut self,
        text: &str,
        style: &TStyle,
        pos: BackendCoord,
    ) -> Result<(), DrawingErrorKind<Self::ErrorType>> {
        common::draw_text(self.snapshot, &self.layout, text, style, pos)
    }
}