1use super::{Drawable, PointCollection};
2use crate::style::{Color, ShapeStyle, SizeDesc};
3use plotters_backend::{BackendCoord, DrawingBackend, DrawingErrorKind};
4
5pub struct Pixel<Coord> {
7 pos: Coord,
8 style: ShapeStyle,
9}
10
11impl<Coord> Pixel<Coord> {
12 pub fn new<P: Into<Coord>, S: Into<ShapeStyle>>(pos: P, style: S) -> Self {
13 Self {
14 pos: pos.into(),
15 style: style.into(),
16 }
17 }
18}
19
20impl<'a, Coord> PointCollection<'a, Coord> for &'a Pixel<Coord> {
21 type Point = &'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<Coord, DB: DrawingBackend> Drawable<DB> for Pixel<Coord> {
29 fn draw<I: Iterator<Item = BackendCoord>>(
30 &self,
31 mut points: I,
32 backend: &mut DB,
33 _: (u32, u32),
34 ) -> Result<(), DrawingErrorKind<DB::ErrorType>> {
35 if let Some((x, y)) = points.next() {
36 return backend.draw_pixel((x, y), self.style.color.to_backend_color());
37 }
38 Ok(())
39 }
40}
41
42#[cfg(test)]
43#[test]
44fn test_pixel_element() {
45 use crate::prelude::*;
46 let da = crate::create_mocked_drawing_area(300, 300, |m| {
47 m.check_draw_pixel(|c, (x, y)| {
48 assert_eq!(x, 150);
49 assert_eq!(y, 152);
50 assert_eq!(c, RED.to_rgba());
51 });
52
53 m.drop_check(|b| {
54 assert_eq!(b.num_draw_pixel_call, 1);
55 assert_eq!(b.draw_count, 1);
56 });
57 });
58 da.draw(&Pixel::new((150, 152), &RED))
59 .expect("Drawing Failure");
60}
61
62#[deprecated(note = "Use new name PathElement instead")]
63pub type Path<Coord> = PathElement<Coord>;
64
65pub struct PathElement<Coord> {
67 points: Vec<Coord>,
68 style: ShapeStyle,
69}
70impl<Coord> PathElement<Coord> {
71 pub fn new<P: Into<Vec<Coord>>, S: Into<ShapeStyle>>(points: P, style: S) -> Self {
76 Self {
77 points: points.into(),
78 style: style.into(),
79 }
80 }
81}
82
83impl<'a, Coord> PointCollection<'a, Coord> for &'a PathElement<Coord> {
84 type Point = &'a Coord;
85 type IntoIter = &'a [Coord];
86 fn point_iter(self) -> &'a [Coord] {
87 &self.points
88 }
89}
90
91impl<Coord, DB: DrawingBackend> Drawable<DB> for PathElement<Coord> {
92 fn draw<I: Iterator<Item = BackendCoord>>(
93 &self,
94 points: I,
95 backend: &mut DB,
96 _: (u32, u32),
97 ) -> Result<(), DrawingErrorKind<DB::ErrorType>> {
98 backend.draw_path(points, &self.style)
99 }
100}
101
102#[cfg(test)]
103#[test]
104fn test_path_element() {
105 use crate::prelude::*;
106 let da = crate::create_mocked_drawing_area(300, 300, |m| {
107 m.check_draw_path(|c, s, path| {
108 assert_eq!(c, BLUE.to_rgba());
109 assert_eq!(s, 5);
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(&PathElement::new(
118 vec![(100, 101), (105, 107), (150, 157)],
119 Into::<ShapeStyle>::into(&BLUE).stroke_width(5),
120 ))
121 .expect("Drawing Failure");
122}
123
124pub struct Rectangle<Coord> {
126 points: [Coord; 2],
127 style: ShapeStyle,
128 margin: (u32, u32, u32, u32),
129}
130
131impl<Coord> Rectangle<Coord> {
132 pub fn new<S: Into<ShapeStyle>>(points: [Coord; 2], style: S) -> Self {
137 Self {
138 points,
139 style: style.into(),
140 margin: (0, 0, 0, 0),
141 }
142 }
143
144 pub fn set_margin(&mut self, t: u32, b: u32, l: u32, r: u32) -> &mut Self {
150 self.margin = (t, b, l, r);
151 self
152 }
153}
154
155impl<'a, Coord> PointCollection<'a, Coord> for &'a Rectangle<Coord> {
156 type Point = &'a Coord;
157 type IntoIter = &'a [Coord];
158 fn point_iter(self) -> &'a [Coord] {
159 &self.points
160 }
161}
162
163impl<Coord, DB: DrawingBackend> Drawable<DB> for Rectangle<Coord> {
164 fn draw<I: Iterator<Item = BackendCoord>>(
165 &self,
166 mut points: I,
167 backend: &mut DB,
168 _: (u32, u32),
169 ) -> Result<(), DrawingErrorKind<DB::ErrorType>> {
170 match (points.next(), points.next()) {
171 (Some(a), Some(b)) => {
172 let (mut a, mut b) = ((a.0.min(b.0), a.1.min(b.1)), (a.0.max(b.0), a.1.max(b.1)));
173 a.1 += self.margin.0 as i32;
174 b.1 -= self.margin.1 as i32;
175 a.0 += self.margin.2 as i32;
176 b.0 -= self.margin.3 as i32;
177 backend.draw_rect(a, b, &self.style, self.style.filled)
178 }
179 _ => Ok(()),
180 }
181 }
182}
183
184#[cfg(test)]
185#[test]
186fn test_rect_element() {
187 use crate::prelude::*;
188 {
189 let da = crate::create_mocked_drawing_area(300, 300, |m| {
190 m.check_draw_rect(|c, s, f, u, d| {
191 assert_eq!(c, BLUE.to_rgba());
192 assert_eq!(f, false);
193 assert_eq!(s, 5);
194 assert_eq!([u, d], [(100, 101), (105, 107)]);
195 });
196 m.drop_check(|b| {
197 assert_eq!(b.num_draw_rect_call, 1);
198 assert_eq!(b.draw_count, 1);
199 });
200 });
201 da.draw(&Rectangle::new(
202 [(100, 101), (105, 107)],
203 Color::stroke_width(&BLUE, 5),
204 ))
205 .expect("Drawing Failure");
206 }
207
208 {
209 let da = crate::create_mocked_drawing_area(300, 300, |m| {
210 m.check_draw_rect(|c, _, f, u, d| {
211 assert_eq!(c, BLUE.to_rgba());
212 assert_eq!(f, true);
213 assert_eq!([u, d], [(100, 101), (105, 107)]);
214 });
215 m.drop_check(|b| {
216 assert_eq!(b.num_draw_rect_call, 1);
217 assert_eq!(b.draw_count, 1);
218 });
219 });
220 da.draw(&Rectangle::new([(100, 101), (105, 107)], BLUE.filled()))
221 .expect("Drawing Failure");
222 }
223}
224
225pub struct Circle<Coord, Size: SizeDesc> {
227 center: Coord,
228 size: Size,
229 style: ShapeStyle,
230}
231
232impl<Coord, Size: SizeDesc> Circle<Coord, Size> {
233 pub fn new<S: Into<ShapeStyle>>(coord: Coord, size: Size, style: S) -> Self {
239 Self {
240 center: coord,
241 size,
242 style: style.into(),
243 }
244 }
245}
246
247impl<'a, Coord, Size: SizeDesc> PointCollection<'a, Coord> for &'a Circle<Coord, Size> {
248 type Point = &'a Coord;
249 type IntoIter = std::iter::Once<&'a Coord>;
250 fn point_iter(self) -> std::iter::Once<&'a Coord> {
251 std::iter::once(&self.center)
252 }
253}
254
255impl<Coord, DB: DrawingBackend, Size: SizeDesc> Drawable<DB> for Circle<Coord, Size> {
256 fn draw<I: Iterator<Item = BackendCoord>>(
257 &self,
258 mut points: I,
259 backend: &mut DB,
260 ps: (u32, u32),
261 ) -> Result<(), DrawingErrorKind<DB::ErrorType>> {
262 if let Some((x, y)) = points.next() {
263 let size = self.size.in_pixels(&ps).max(0) as u32;
264 return backend.draw_circle((x, y), size, &self.style, self.style.filled);
265 }
266 Ok(())
267 }
268}
269
270#[cfg(test)]
271#[test]
272fn test_circle_element() {
273 use crate::prelude::*;
274 let da = crate::create_mocked_drawing_area(300, 300, |m| {
275 m.check_draw_circle(|c, _, f, s, r| {
276 assert_eq!(c, BLUE.to_rgba());
277 assert_eq!(f, false);
278 assert_eq!(s, (150, 151));
279 assert_eq!(r, 20);
280 });
281 m.drop_check(|b| {
282 assert_eq!(b.num_draw_circle_call, 1);
283 assert_eq!(b.draw_count, 1);
284 });
285 });
286 da.draw(&Circle::new((150, 151), 20, &BLUE))
287 .expect("Drawing Failure");
288}
289
290pub struct Polygon<Coord> {
292 points: Vec<Coord>,
293 style: ShapeStyle,
294}
295impl<Coord> Polygon<Coord> {
296 pub fn new<P: Into<Vec<Coord>>, S: Into<ShapeStyle>>(points: P, style: S) -> Self {
301 Self {
302 points: points.into(),
303 style: style.into(),
304 }
305 }
306}
307
308impl<'a, Coord> PointCollection<'a, Coord> for &'a Polygon<Coord> {
309 type Point = &'a Coord;
310 type IntoIter = &'a [Coord];
311 fn point_iter(self) -> &'a [Coord] {
312 &self.points
313 }
314}
315
316impl<Coord, DB: DrawingBackend> Drawable<DB> for Polygon<Coord> {
317 fn draw<I: Iterator<Item = BackendCoord>>(
318 &self,
319 points: I,
320 backend: &mut DB,
321 _: (u32, u32),
322 ) -> Result<(), DrawingErrorKind<DB::ErrorType>> {
323 backend.fill_polygon(points, &self.style.color.to_backend_color())
324 }
325}
326
327#[cfg(test)]
328#[test]
329fn test_polygon_element() {
330 use crate::prelude::*;
331 let points = vec![(100, 100), (50, 500), (300, 400), (200, 300), (550, 200)];
332 let expected_points = points.clone();
333
334 let da = crate::create_mocked_drawing_area(800, 800, |m| {
335 m.check_fill_polygon(move |c, p| {
336 assert_eq!(c, BLUE.to_rgba());
337 assert_eq!(expected_points.len(), p.len());
338 assert_eq!(expected_points, p);
339 });
340 m.drop_check(|b| {
341 assert_eq!(b.num_fill_polygon_call, 1);
342 assert_eq!(b.draw_count, 1);
343 });
344 });
345
346 da.draw(&Polygon::new(points.clone(), &BLUE))
347 .expect("Drawing Failure");
348}