1pub use crate::*;
2
3use core::convert::Infallible;
4use embedded_graphics_core::Pixel;
5use embedded_graphics_core::{prelude::*, primitives::*};
6
7pub trait BufferStrategy: DrawTarget {
8 fn flush<T: DrawTarget<Color = Self::Color>>(&mut self, target: &mut T)
9 -> Result<(), T::Error>;
10}
11
12pub trait HasFramebuffer<C, const N: usize, const W: usize, const H: usize>
13where
14 C: RgbColor,
15{
16 fn current_mut(&mut self) -> &mut Framebuffer<C, N, W, H>;
17}
18
19pub struct DoubleBuffer<C, const N: usize, const W: usize, const H: usize>
21where
22 C: RgbColor,
23{
24 current: Framebuffer<C, N, W, H>,
25 reference: Framebuffer<C, N, W, H>,
26}
27
28impl<C, const N: usize, const W: usize, const H: usize> DoubleBuffer<C, N, W, H>
29where
30 C: RgbColor,
31{
32 pub fn new() -> Self {
33 Self {
34 current: Framebuffer::new(),
35 reference: Framebuffer::new(),
36 }
37 }
38}
39
40impl<C, const N: usize, const W: usize, const H: usize> DrawTarget for DoubleBuffer<C, N, W, H>
41where
42 C: RgbColor,
43{
44 type Color = C;
45 type Error = Infallible;
46
47 fn draw_iter<I>(&mut self, pixels: I) -> Result<(), Self::Error>
48 where
49 I: IntoIterator<Item = Pixel<Self::Color>>,
50 {
51 self.current.draw_iter(pixels)
52 }
53
54 fn fill_contiguous<I>(&mut self, area: &Rectangle, colors: I) -> Result<(), Self::Error>
55 where
56 I: IntoIterator<Item = Self::Color>,
57 {
58 self.current.fill_contiguous(area, colors)
59 }
60
61 fn fill_solid(&mut self, area: &Rectangle, color: C) -> Result<(), Self::Error> {
62 self.current.fill_solid(area, color)
63 }
64
65 fn clear(&mut self, color: C) -> Result<(), Self::Error> {
66 self.current.clear(color)
67 }
68}
69
70impl<C, const N: usize, const W: usize, const H: usize> OriginDimensions
71 for DoubleBuffer<C, N, W, H>
72where
73 C: RgbColor,
74{
75 fn size(&self) -> Size {
76 Size::new(W as u32, H as u32)
77 }
78}
79
80impl<C, const N: usize, const W: usize, const H: usize> BufferStrategy for DoubleBuffer<C, N, W, H>
81where
82 C: RgbColor,
83{
84 fn flush<T>(&mut self, target: &mut T) -> Result<(), T::Error>
85 where
86 T: DrawTarget<Color = Self::Color>,
87 {
88 let rect = Rectangle::new(Point::zero(), Size::new(W as u32, H as u32));
89 target.fill_contiguous(&rect, self.current.iter_colors())?;
90 core::mem::swap(&mut self.reference, &mut self.current);
91 Ok(())
92 }
93}
94
95impl<C, const N: usize, const W: usize, const H: usize> HasFramebuffer<C, N, W, H>
96 for DoubleBuffer<C, N, W, H>
97where
98 C: RgbColor,
99{
100 fn current_mut(&mut self) -> &mut Framebuffer<C, N, W, H> {
101 &mut self.current
102 }
103}
104
105pub struct SingleBuffer<C, const N: usize, const W: usize, const H: usize>
107where
108 C: RgbColor,
109{
110 current: Framebuffer<C, N, W, H>,
111}
112
113impl<C, const N: usize, const W: usize, const H: usize> SingleBuffer<C, N, W, H>
114where
115 C: RgbColor,
116{
117 pub fn new() -> Self {
118 Self {
119 current: Framebuffer::new(),
120 }
121 }
122}
123
124impl<C, const N: usize, const W: usize, const H: usize> BufferStrategy for SingleBuffer<C, N, W, H>
125where
126 C: RgbColor,
127{
128 fn flush<T>(&mut self, target: &mut T) -> Result<(), T::Error>
129 where
130 T: DrawTarget<Color = Self::Color>,
131 {
132 let rect = Rectangle::new(Point::zero(), Size::new(W as u32, H as u32));
133 target.fill_contiguous(&rect, self.current.iter_colors())
134 }
135}
136
137impl<C, const N: usize, const W: usize, const H: usize> DrawTarget for SingleBuffer<C, N, W, H>
138where
139 C: RgbColor,
140{
141 type Color = C;
142 type Error = Infallible;
143
144 fn draw_iter<I>(&mut self, pixels: I) -> Result<(), Self::Error>
145 where
146 I: IntoIterator<Item = Pixel<Self::Color>>,
147 {
148 self.current.draw_iter(pixels)
149 }
150
151 fn fill_contiguous<I>(&mut self, area: &Rectangle, colors: I) -> Result<(), Self::Error>
152 where
153 I: IntoIterator<Item = Self::Color>,
154 {
155 self.current.fill_contiguous(area, colors)
156 }
157
158 fn fill_solid(&mut self, area: &Rectangle, color: C) -> Result<(), Self::Error> {
159 self.current.fill_solid(area, color)
160 }
161
162 fn clear(&mut self, color: C) -> Result<(), Self::Error> {
163 self.current.clear(color)
164 }
165}
166
167impl<C, const N: usize, const W: usize, const H: usize> OriginDimensions
168 for SingleBuffer<C, N, W, H>
169where
170 C: RgbColor,
171{
172 fn size(&self) -> Size {
173 Size::new(W as u32, H as u32)
174 }
175}
176
177impl<C, const N: usize, const W: usize, const H: usize> HasFramebuffer<C, N, W, H>
178 for SingleBuffer<C, N, W, H>
179where
180 C: RgbColor,
181{
182 fn current_mut(&mut self) -> &mut Framebuffer<C, N, W, H> {
183 &mut self.current
184 }
185}
186
187pub struct Canvas<'a, T, S>
188where
189 T: DrawTarget,
190 S: BufferStrategy<Color = T::Color>,
191{
192 strategy: S,
193 target: &'a mut T,
194}
195
196impl<'a, T, S> Canvas<'a, T, S>
197where
198 T: DrawTarget,
199 S: BufferStrategy<Color = T::Color>,
200{
201 pub fn with_strategy(target: &'a mut T, strategy: S) -> Self {
203 Self { strategy, target }
204 }
205
206 pub fn flush(&mut self) -> Result<(), T::Error> {
208 self.strategy.flush(self.target)
209 }
210}
211
212impl<'a, T, S> OriginDimensions for Canvas<'a, T, S>
213where
214 T: DrawTarget + OriginDimensions,
215 S: BufferStrategy<Color = T::Color>,
216{
217 fn size(&self) -> Size {
218 self.target.size()
219 }
220}
221
222impl<'a, T, C, const N: usize, const W: usize, const H: usize>
223 Canvas<'a, T, DoubleBuffer<C, N, W, H>>
224where
225 C: RgbColor,
226 T: DrawTarget<Color = C>,
227{
228 pub fn double_buffered(target: &'a mut T) -> Self {
229 Self::with_strategy(target, DoubleBuffer::new())
230 }
231}
232
233impl<'a, T, C, const N: usize, const W: usize, const H: usize>
234 Canvas<'a, T, SingleBuffer<C, N, W, H>>
235where
236 C: RgbColor,
237 T: DrawTarget<Color = C>,
238{
239 pub fn single_buffered(target: &'a mut T) -> Self {
240 Self::with_strategy(target, SingleBuffer::new())
241 }
242}
243
244impl<'a, T, S> Canvas<'a, T, S>
245where
246 T: DrawTarget,
247 S: BufferStrategy<Color = T::Color>,
248 T::Color: RgbColor,
249 Rgba<S::Color>: Blend<S::Color>,
250{
251 pub fn alpha<const N: usize, const W: usize, const H: usize>(
252 &mut self,
253 ) -> AlphaCanvas<'_, S::Color, N, W, H>
254 where
255 S: HasFramebuffer<S::Color, N, W, H>,
256 {
257 AlphaCanvas::new(self.strategy.current_mut())
258 }
259}
260
261impl<'a, T, S> DrawTarget for Canvas<'a, T, S>
262where
263 T: DrawTarget + OriginDimensions,
264 S: BufferStrategy<Color = T::Color>,
265{
266 type Error = S::Error;
267 type Color = S::Color;
268
269 fn draw_iter<I>(&mut self, pixels: I) -> Result<(), S::Error>
270 where
271 I: IntoIterator<Item = Pixel<Self::Color>>,
272 {
273 self.strategy.draw_iter(pixels)
274 }
275
276 fn fill_contiguous<I>(&mut self, area: &Rectangle, colors: I) -> Result<(), S::Error>
277 where
278 I: IntoIterator<Item = Self::Color>,
279 {
280 self.strategy.fill_contiguous(area, colors)
281 }
282
283 fn fill_solid(&mut self, area: &Rectangle, color: Self::Color) -> Result<(), S::Error> {
284 self.strategy.fill_solid(area, color)
285 }
286
287 fn clear(&mut self, color: Self::Color) -> Result<(), S::Error> {
288 self.strategy.clear(color)
289 }
290}