1 use super::*; 2 use plotters_backend::DrawingBackend; 3 use std::borrow::Borrow; 4 use std::iter::{once, Once}; 5 use std::marker::PhantomData; 6 use std::ops::Add; 7 8 /// An empty composable element, which is the start point of an ad-hoc composable element 9 pub struct EmptyElement<Coord, DB: DrawingBackend> { 10 coord: Coord, 11 phantom: PhantomData<DB>, 12 } 13 14 impl<Coord, DB: DrawingBackend> EmptyElement<Coord, DB> { at(coord: Coord) -> Self15 pub fn at(coord: Coord) -> Self { 16 Self { 17 coord, 18 phantom: PhantomData, 19 } 20 } 21 } 22 23 impl<Coord, Other, DB: DrawingBackend> Add<Other> for EmptyElement<Coord, DB> 24 where 25 Other: Drawable<DB>, 26 for<'a> &'a Other: PointCollection<'a, BackendCoord>, 27 { 28 type Output = BoxedElement<Coord, DB, Other>; add(self, other: Other) -> Self::Output29 fn add(self, other: Other) -> Self::Output { 30 BoxedElement { 31 offset: self.coord, 32 inner: other, 33 phantom: PhantomData, 34 } 35 } 36 } 37 38 impl<'a, Coord, DB: DrawingBackend> PointCollection<'a, Coord> for &'a EmptyElement<Coord, DB> { 39 type Point = &'a Coord; 40 type IntoIter = Once<&'a Coord>; point_iter(self) -> Self::IntoIter41 fn point_iter(self) -> Self::IntoIter { 42 once(&self.coord) 43 } 44 } 45 46 impl<Coord, DB: DrawingBackend> Drawable<DB> for EmptyElement<Coord, DB> { draw<I: Iterator<Item = BackendCoord>>( &self, _pos: I, _backend: &mut DB, _: (u32, u32), ) -> Result<(), DrawingErrorKind<DB::ErrorType>>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 58 pub struct BoxedElement<Coord, DB: DrawingBackend, A: Drawable<DB>> { 59 inner: A, 60 offset: Coord, 61 phantom: PhantomData<DB>, 62 } 63 64 impl<'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>; point_iter(self) -> Self::IntoIter69 fn point_iter(self) -> Self::IntoIter { 70 once(&self.offset) 71 } 72 } 73 74 impl<Coord, DB: DrawingBackend, A> Drawable<DB> for BoxedElement<Coord, DB, A> 75 where 76 for<'a> &'a A: PointCollection<'a, BackendCoord>, 77 A: Drawable<DB>, 78 { draw<I: Iterator<Item = BackendCoord>>( &self, mut pos: I, backend: &mut DB, ps: (u32, u32), ) -> Result<(), DrawingErrorKind<DB::ErrorType>>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 99 impl<Coord, DB: DrawingBackend, My, Yours> Add<Yours> for BoxedElement<Coord, DB, My> 100 where 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>; add(self, yours: Yours) -> Self::Output107 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 118 pub struct ComposedElement<Coord, DB: DrawingBackend, A, B> 119 where 120 A: Drawable<DB>, 121 B: Drawable<DB>, 122 { 123 first: A, 124 second: B, 125 offset: Coord, 126 phantom: PhantomData<DB>, 127 } 128 129 impl<'b, Coord, DB: DrawingBackend, A, B> PointCollection<'b, Coord> 130 for &'b ComposedElement<Coord, DB, A, B> 131 where 132 A: Drawable<DB>, 133 B: Drawable<DB>, 134 { 135 type Point = &'b Coord; 136 type IntoIter = Once<&'b Coord>; point_iter(self) -> Self::IntoIter137 fn point_iter(self) -> Self::IntoIter { 138 once(&self.offset) 139 } 140 } 141 142 impl<Coord, DB: DrawingBackend, A, B> Drawable<DB> for ComposedElement<Coord, DB, A, B> 143 where 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 { draw<I: Iterator<Item = BackendCoord>>( &self, mut pos: I, backend: &mut DB, ps: (u32, u32), ) -> Result<(), DrawingErrorKind<DB::ErrorType>>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 177 impl<Coord, DB: DrawingBackend, A, B, C> Add<C> for ComposedElement<Coord, DB, A, B> 178 where 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>>; add(self, rhs: C) -> Self::Output187 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 } 201