plotters/element/
composable.rs

1use super::*;
2use plotters_backend::DrawingBackend;
3use std::borrow::Borrow;
4use std::iter::{once, Once};
5use std::marker::PhantomData;
6use std::ops::Add;
7
8/// An empty composable element, which is the start point of an ad-hoc composable element
9pub struct EmptyElement<Coord, DB: DrawingBackend> {
10    coord: Coord,
11    phantom: PhantomData<DB>,
12}
13
14impl<Coord, DB: DrawingBackend> EmptyElement<Coord, DB> {
15    pub fn at(coord: Coord) -> Self {
16        Self {
17            coord,
18            phantom: PhantomData,
19        }
20    }
21}
22
23impl<Coord, Other, DB: DrawingBackend> Add<Other> for EmptyElement<Coord, DB>
24where
25    Other: Drawable<DB>,
26    for<'a> &'a Other: PointCollection<'a, BackendCoord>,
27{
28    type Output = BoxedElement<Coord, DB, Other>;
29    fn add(self, other: Other) -> Self::Output {
30        BoxedElement {
31            offset: self.coord,
32            inner: other,
33            phantom: PhantomData,
34        }
35    }
36}
37
38impl<'a, Coord, DB: DrawingBackend> PointCollection<'a, Coord> for &'a EmptyElement<Coord, DB> {
39    type Point = &'a Coord;
40    type IntoIter = Once<&'a Coord>;
41    fn point_iter(self) -> Self::IntoIter {
42        once(&self.coord)
43    }
44}
45
46impl<Coord, DB: DrawingBackend> Drawable<DB> for EmptyElement<Coord, DB> {
47    fn draw<I: Iterator<Item = BackendCoord>>(
48        &self,
49        _pos: I,
50        _backend: &mut DB,
51        _: (u32, u32),
52    ) -> Result<(), DrawingErrorKind<DB::ErrorType>> {
53        Ok(())
54    }
55}
56
57/// An composed element has only one component
58pub struct BoxedElement<Coord, DB: DrawingBackend, A: Drawable<DB>> {
59    inner: A,
60    offset: Coord,
61    phantom: PhantomData<DB>,
62}
63
64impl<'b, Coord, DB: DrawingBackend, A: Drawable<DB>> PointCollection<'b, Coord>
65    for &'b BoxedElement<Coord, DB, A>
66{
67    type Point = &'b Coord;
68    type IntoIter = Once<&'b Coord>;
69    fn point_iter(self) -> Self::IntoIter {
70        once(&self.offset)
71    }
72}
73
74impl<Coord, DB: DrawingBackend, A> Drawable<DB> for BoxedElement<Coord, DB, A>
75where
76    for<'a> &'a A: PointCollection<'a, BackendCoord>,
77    A: Drawable<DB>,
78{
79    fn draw<I: Iterator<Item = BackendCoord>>(
80        &self,
81        mut pos: I,
82        backend: &mut DB,
83        ps: (u32, u32),
84    ) -> Result<(), DrawingErrorKind<DB::ErrorType>> {
85        if let Some((x0, y0)) = pos.next() {
86            self.inner.draw(
87                self.inner.point_iter().into_iter().map(|p| {
88                    let p = p.borrow();
89                    (p.0 + x0, p.1 + y0)
90                }),
91                backend,
92                ps,
93            )?;
94        }
95        Ok(())
96    }
97}
98
99impl<Coord, DB: DrawingBackend, My, Yours> Add<Yours> for BoxedElement<Coord, DB, My>
100where
101    My: Drawable<DB>,
102    for<'a> &'a My: PointCollection<'a, BackendCoord>,
103    Yours: Drawable<DB>,
104    for<'a> &'a Yours: PointCollection<'a, BackendCoord>,
105{
106    type Output = ComposedElement<Coord, DB, My, Yours>;
107    fn add(self, yours: Yours) -> Self::Output {
108        ComposedElement {
109            offset: self.offset,
110            first: self.inner,
111            second: yours,
112            phantom: PhantomData,
113        }
114    }
115}
116
117/// The composed element which has at least two components
118pub struct ComposedElement<Coord, DB: DrawingBackend, A, B>
119where
120    A: Drawable<DB>,
121    B: Drawable<DB>,
122{
123    first: A,
124    second: B,
125    offset: Coord,
126    phantom: PhantomData<DB>,
127}
128
129impl<'b, Coord, DB: DrawingBackend, A, B> PointCollection<'b, Coord>
130    for &'b ComposedElement<Coord, DB, A, B>
131where
132    A: Drawable<DB>,
133    B: Drawable<DB>,
134{
135    type Point = &'b Coord;
136    type IntoIter = Once<&'b Coord>;
137    fn point_iter(self) -> Self::IntoIter {
138        once(&self.offset)
139    }
140}
141
142impl<Coord, DB: DrawingBackend, A, B> Drawable<DB> for ComposedElement<Coord, DB, A, B>
143where
144    for<'a> &'a A: PointCollection<'a, BackendCoord>,
145    for<'b> &'b B: PointCollection<'b, BackendCoord>,
146    A: Drawable<DB>,
147    B: Drawable<DB>,
148{
149    fn draw<I: Iterator<Item = BackendCoord>>(
150        &self,
151        mut pos: I,
152        backend: &mut DB,
153        ps: (u32, u32),
154    ) -> Result<(), DrawingErrorKind<DB::ErrorType>> {
155        if let Some((x0, y0)) = pos.next() {
156            self.first.draw(
157                self.first.point_iter().into_iter().map(|p| {
158                    let p = p.borrow();
159                    (p.0 + x0, p.1 + y0)
160                }),
161                backend,
162                ps,
163            )?;
164            self.second.draw(
165                self.second.point_iter().into_iter().map(|p| {
166                    let p = p.borrow();
167                    (p.0 + x0, p.1 + y0)
168                }),
169                backend,
170                ps,
171            )?;
172        }
173        Ok(())
174    }
175}
176
177impl<Coord, DB: DrawingBackend, A, B, C> Add<C> for ComposedElement<Coord, DB, A, B>
178where
179    A: Drawable<DB>,
180    for<'a> &'a A: PointCollection<'a, BackendCoord>,
181    B: Drawable<DB>,
182    for<'a> &'a B: PointCollection<'a, BackendCoord>,
183    C: Drawable<DB>,
184    for<'a> &'a C: PointCollection<'a, BackendCoord>,
185{
186    type Output = ComposedElement<Coord, DB, A, ComposedElement<BackendCoord, DB, B, C>>;
187    fn add(self, rhs: C) -> Self::Output {
188        ComposedElement {
189            offset: self.offset,
190            first: self.first,
191            second: ComposedElement {
192                offset: (0, 0),
193                first: self.second,
194                second: rhs,
195                phantom: PhantomData,
196            },
197            phantom: PhantomData,
198        }
199    }
200}