plotters_unsable/element/
basic_shapes.rs

1use super::{Drawable, PointCollection};
2use crate::drawing::backend::{BackendCoord, DrawingBackend, DrawingErrorKind};
3use crate::style::ShapeStyle;
4
5/// An element of a single pixel
6pub struct Pixel<'a, Coord> {
7    pos: Coord,
8    style: ShapeStyle<'a>,
9}
10
11impl<'a, Coord> Pixel<'a, Coord> {
12    pub fn new<P: Into<Coord>, S: Into<ShapeStyle<'a>>>(pos: P, style: S) -> Self {
13        Self {
14            pos: pos.into(),
15            style: style.into(),
16        }
17    }
18}
19
20impl<'b, 'a, Coord: 'a> PointCollection<'a, Coord> for &'a Pixel<'b, Coord> {
21    type Borrow = &'a Coord;
22    type IntoIter = std::iter::Once<&'a Coord>;
23    fn point_iter(self) -> Self::IntoIter {
24        std::iter::once(&self.pos)
25    }
26}
27
28impl<'a, Coord: 'a, DB: DrawingBackend> Drawable<DB> for Pixel<'a, Coord> {
29    fn draw<I: Iterator<Item = BackendCoord>>(
30        &self,
31        mut points: I,
32        backend: &mut DB,
33    ) -> Result<(), DrawingErrorKind<DB::ErrorType>> {
34        if let Some((x, y)) = points.next() {
35            return backend.draw_pixel((x, y), &Box::new(self.style.color));
36        }
37        Ok(())
38    }
39}
40
41#[cfg(test)]
42#[test]
43fn test_pixel_element() {
44    use crate::prelude::*;
45    let da = crate::create_mocked_drawing_area(300, 300, |m| {
46        m.check_draw_pixel(|c, (x, y)| {
47            assert_eq!(x, 150);
48            assert_eq!(y, 152);
49            assert_eq!(c.0, 255);
50            assert_eq!(c.1, 0);
51            assert_eq!(c.2, 0);
52            assert_eq!(c.3, 1.0);
53        });
54
55        m.drop_check(|b| {
56            assert_eq!(b.num_draw_pixel_call, 1);
57            assert_eq!(b.draw_count, 1);
58        });
59    });
60    da.draw(&Pixel::new((150, 152), &Red))
61        .expect("Drawing Failure");
62}
63
64/// An element of a series of connected lines
65pub struct Path<'a, Coord> {
66    points: Vec<Coord>,
67    style: ShapeStyle<'a>,
68}
69impl<'a, Coord> Path<'a, Coord> {
70    /// Create a new path
71    /// - `points`: The iterator of the points
72    /// - `style`: The shape style
73    /// - returns the created element
74    pub fn new<P: Into<Vec<Coord>>, S: Into<ShapeStyle<'a>>>(points: P, style: S) -> Self {
75        Self {
76            points: points.into(),
77            style: style.into(),
78        }
79    }
80}
81
82impl<'b, 'a, Coord: 'a> PointCollection<'a, Coord> for &'a Path<'b, Coord> {
83    type Borrow = &'a Coord;
84    type IntoIter = &'a [Coord];
85    fn point_iter(self) -> &'a [Coord] {
86        &self.points
87    }
88}
89
90impl<'a, Coord: 'a, DB: DrawingBackend> Drawable<DB> for Path<'a, Coord> {
91    fn draw<I: Iterator<Item = BackendCoord>>(
92        &self,
93        points: I,
94        backend: &mut DB,
95    ) -> Result<(), DrawingErrorKind<DB::ErrorType>> {
96        backend.draw_path(points, &Box::new(self.style.color))
97    }
98}
99
100#[cfg(test)]
101#[test]
102fn test_path_element() {
103    use crate::prelude::*;
104    let da = crate::create_mocked_drawing_area(300, 300, |m| {
105        m.check_draw_path(|c, path| {
106            assert_eq!(c.0, 0);
107            assert_eq!(c.1, 0);
108            assert_eq!(c.2, 255);
109            assert_eq!(c.3, 1.0);
110            assert_eq!(path, vec![(100, 101), (105, 107), (150, 157)]);
111        });
112        m.drop_check(|b| {
113            assert_eq!(b.num_draw_path_call, 1);
114            assert_eq!(b.draw_count, 1);
115        });
116    });
117    da.draw(&Path::new(vec![(100, 101), (105, 107), (150, 157)], &Blue))
118        .expect("Drawing Failure");
119}
120
121/// A rectangle element
122pub struct Rectangle<'a, Coord> {
123    points: [Coord; 2],
124    style: ShapeStyle<'a>,
125    margin: (u32, u32, u32, u32),
126}
127
128impl<'a, Coord> Rectangle<'a, Coord> {
129    /// Create a new path
130    /// - `points`: The left upper and right lower coner of the rectangle
131    /// - `style`: The shape style
132    /// - returns the created element
133    pub fn new<S: Into<ShapeStyle<'a>>>(points: [Coord; 2], style: S) -> Self {
134        Self {
135            points,
136            style: style.into(),
137            margin: (0, 0, 0, 0),
138        }
139    }
140
141    /// Set the margin of the rectangle
142    /// - `t`: The top margin
143    /// - `b`: The bottom margin
144    /// - `l`: The left margin
145    /// - `r`: The right margin
146    pub fn set_margin(&mut self, t: u32, b: u32, l: u32, r: u32) -> &mut Self {
147        self.margin = (t, b, l, r);
148        self
149    }
150}
151
152impl<'b, 'a, Coord: 'a> PointCollection<'a, Coord> for &'a Rectangle<'b, Coord> {
153    type Borrow = &'a Coord;
154    type IntoIter = &'a [Coord];
155    fn point_iter(self) -> &'a [Coord] {
156        &self.points
157    }
158}
159
160impl<'a, Coord: 'a, DB: DrawingBackend> Drawable<DB> for Rectangle<'a, Coord> {
161    fn draw<I: Iterator<Item = BackendCoord>>(
162        &self,
163        mut points: I,
164        backend: &mut DB,
165    ) -> Result<(), DrawingErrorKind<DB::ErrorType>> {
166        match (points.next(), points.next()) {
167            (Some(mut a), Some(mut b)) => {
168                a.1 += self.margin.0 as i32;
169                b.1 -= self.margin.1 as i32;
170                a.0 += self.margin.2 as i32;
171                b.0 -= self.margin.3 as i32;
172                backend.draw_rect(a, b, &Box::new(self.style.color), self.style.filled)
173            }
174            _ => Ok(()),
175        }
176    }
177}
178
179#[cfg(test)]
180#[test]
181fn test_rect_element() {
182    use crate::prelude::*;
183    let da = crate::create_mocked_drawing_area(300, 300, |m| {
184        m.check_draw_rect(|c, f, u, d| {
185            assert_eq!(c.0, 0);
186            assert_eq!(c.1, 0);
187            assert_eq!(c.2, 255);
188            assert_eq!(c.3, 1.0);
189            assert_eq!(f, false);
190            assert_eq!([u, d], [(100, 101), (105, 107)]);
191        });
192        m.drop_check(|b| {
193            assert_eq!(b.num_draw_rect_call, 1);
194            assert_eq!(b.draw_count, 1);
195        });
196    });
197    da.draw(&Rectangle::new([(100, 101), (105, 107)], &Blue))
198        .expect("Drawing Failure");
199}
200
201/// A circle element
202pub struct Circle<'a, Coord> {
203    center: Coord,
204    size: u32,
205    style: ShapeStyle<'a>,
206}
207
208impl<'a, Coord> Circle<'a, Coord> {
209    /// Create a new circle element
210    /// - `coord` The center of the circle
211    /// - `size` The radius of the circle
212    /// - `style` The style of the circle
213    /// - Return: The newly created circle element
214    pub fn new<S: Into<ShapeStyle<'a>>>(coord: Coord, size: u32, style: S) -> Self {
215        Self {
216            center: coord,
217            size,
218            style: style.into(),
219        }
220    }
221}
222
223impl<'b, 'a, Coord: 'a> PointCollection<'a, Coord> for &'a Circle<'b, Coord> {
224    type Borrow = &'a Coord;
225    type IntoIter = std::iter::Once<&'a Coord>;
226    fn point_iter(self) -> std::iter::Once<&'a Coord> {
227        std::iter::once(&self.center)
228    }
229}
230
231impl<'a, Coord: 'a, DB: DrawingBackend> Drawable<DB> for Circle<'a, Coord> {
232    fn draw<I: Iterator<Item = BackendCoord>>(
233        &self,
234        mut points: I,
235        backend: &mut DB,
236    ) -> Result<(), DrawingErrorKind<DB::ErrorType>> {
237        if let Some((x, y)) = points.next() {
238            return backend.draw_circle(
239                (x, y),
240                self.size,
241                &Box::new(self.style.color),
242                self.style.filled,
243            );
244        }
245        Ok(())
246    }
247}
248
249#[cfg(test)]
250#[test]
251fn test_circle_element() {
252    use crate::prelude::*;
253    let da = crate::create_mocked_drawing_area(300, 300, |m| {
254        m.check_draw_circle(|c, f, s, r| {
255            assert_eq!(c.0, 0);
256            assert_eq!(c.1, 0);
257            assert_eq!(c.2, 255);
258            assert_eq!(c.3, 1.0);
259            assert_eq!(f, false);
260            assert_eq!(s, (150, 151));
261            assert_eq!(r, 20);
262        });
263        m.drop_check(|b| {
264            assert_eq!(b.num_draw_circle_call, 1);
265            assert_eq!(b.draw_count, 1);
266        });
267    });
268    da.draw(&Circle::new((150, 151), 20, &Blue))
269        .expect("Drawing Failure");
270}