1use display_interface::{DisplayError, WriteOnlyDataCommand};
4
5use crate::{
6 display::{DisplayDefinition, NewZeroed},
7 rotation::DisplayRotation,
8 Gc9a01,
9};
10
11use super::DisplayConfiguration;
12
13use embedded_hal::delay::DelayNs;
14
15#[derive(Debug, Clone)]
22pub struct BufferedGraphics<D>
23where
24 D: DisplayDefinition,
25{
26 buffer: D::Buffer,
27 min_x: u16,
28 max_x: u16,
29 min_y: u16,
30 max_y: u16,
31}
32
33impl<D> BufferedGraphics<D>
34where
35 D: DisplayDefinition,
36{
37 pub(crate) fn new() -> Self {
39 Self {
40 buffer: NewZeroed::new_zeroed(),
41 min_x: u16::MAX,
42 max_x: u16::MIN,
43 min_y: u16::MAX,
44 max_y: u16::MIN,
45 }
46 }
47}
48
49impl<I, D, DELAY> DisplayConfiguration<DELAY> for Gc9a01<I, D, BufferedGraphics<D>>
50where
51 I: WriteOnlyDataCommand,
52 D: DisplayDefinition,
53 DELAY: DelayNs,
54{
55 type Error = DisplayError;
56
57 fn set_rotation(&mut self, rot: DisplayRotation) -> Result<(), DisplayError> {
59 self.set_display_rotation(rot)
60 }
61
62 fn init(&mut self, delay: &mut DELAY) -> Result<(), DisplayError> {
64 self.clear();
65 self.init_with_addr_mode(delay)
66 }
67}
68
69impl<I, D> Gc9a01<I, D, BufferedGraphics<D>>
70where
71 I: WriteOnlyDataCommand,
72 D: DisplayDefinition,
73{
74 pub fn clear(&mut self) {
77 for b in self.mode.buffer.as_mut() {
78 *b = 0;
79 }
80
81 let (max_x, max_y) = self.dimensions();
82 self.mode.min_x = u16::MIN;
83 self.mode.max_x = max_x;
84 self.mode.min_y = u16::MIN;
85 self.mode.max_y = max_y;
86 }
87
88 pub fn fill(&mut self, color: u16) {
89 for b in self.mode.buffer.as_mut() {
90 *b = color;
91 }
92
93 let (max_x, max_y) = self.dimensions();
94 self.mode.min_x = u16::MIN;
95 self.mode.max_x = max_x;
96 self.mode.min_y = u16::MIN;
97 self.mode.max_y = max_y;
98 }
99
100 pub fn flush(&mut self) -> Result<(), DisplayError> {
106 if self.mode.max_x < self.mode.min_x || self.mode.max_y < self.mode.min_y {
108 return Ok(());
109 }
110
111 let (bound_width, bound_height) = self.bounds();
112 let (screen_width, screen_height) = self.dimensions();
113
114 let disp_min_x = self.mode.min_x;
116 let disp_min_y = self.mode.min_y;
117
118 let (disp_max_x, disp_max_y) = (
119 (self.mode.max_x).min(bound_width),
120 (self.mode.max_y).min(bound_height),
121 );
122
123 self.mode.min_x = u16::MAX;
125 self.mode.max_x = u16::MIN;
126 self.mode.min_y = u16::MAX;
127 self.mode.max_y = u16::MIN;
128
129 let offset_x = match self.display_rotation {
130 DisplayRotation::Rotate0 | DisplayRotation::Rotate270 => D::OFFSET_X,
131 DisplayRotation::Rotate90 | DisplayRotation::Rotate180 => {
132 D::COLS - D::WIDTH - D::OFFSET_X
133 }
134 };
135
136 match self.display_rotation {
137 DisplayRotation::Rotate0 | DisplayRotation::Rotate180 => {
138 self.set_draw_area(
139 (disp_min_x + offset_x, disp_min_y + D::OFFSET_Y),
140 (disp_max_x + offset_x, disp_max_y + D::OFFSET_Y),
141 )?;
142
143 Self::flush_buffer_chunks(
144 &mut self.interface,
145 self.mode.buffer.as_mut(),
146 screen_width as usize,
147 (disp_min_x, disp_min_y),
148 (disp_max_x, disp_max_y),
149 )
150 }
151 DisplayRotation::Rotate90 | DisplayRotation::Rotate270 => {
152 self.set_draw_area(
153 (disp_min_y + offset_x, disp_min_x + D::OFFSET_Y),
154 (disp_max_y + offset_x, disp_max_x + D::OFFSET_Y),
155 )?;
156
157 Self::flush_buffer_chunks(
158 &mut self.interface,
159 self.mode.buffer.as_mut(),
160 screen_height as usize,
161 (disp_min_y, disp_min_x),
162 (disp_max_y, disp_max_x),
163 )
164 }
165 }
166 }
167
168 pub fn set_pixels<T>(
175 &mut self,
176 start: (u16, u16),
177 end: (u16, u16),
178 colors: T,
179 ) -> Result<(), DisplayError>
180 where
181 T: IntoIterator<Item = u16>,
182 {
183 let x = start.0;
184 let y = start.1;
185 let rotation = self.display_rotation;
186
187 let idx = match rotation {
188 DisplayRotation::Rotate0 | DisplayRotation::Rotate180 => {
189 ((y as usize) * D::WIDTH as usize) + (x as usize)
190 }
191 DisplayRotation::Rotate90 | DisplayRotation::Rotate270 => {
192 ((x as usize) * D::HEIGHT as usize) + (y as usize)
193 }
194 };
195
196 let mut buffer_index = idx;
197 let buffer_len = self.mode.buffer.as_mut().len();
198
199 for color in colors {
200 if buffer_index >= buffer_len {
201 return Err(DisplayError::OutOfBoundsError);
202 }
203
204 unsafe {
206 *self.mode.buffer.as_mut().get_unchecked_mut(buffer_index) = color;
207 }
208 buffer_index += 1;
209 }
210
211 self.mode.min_x = self.mode.min_x.min(start.0);
212 self.mode.max_x = self.mode.max_x.max(end.0);
213 self.mode.min_y = self.mode.min_y.min(start.1);
214 self.mode.max_y = self.mode.max_y.max(end.1);
215
216 Ok(())
217 }
218
219 pub fn set_pixel(&mut self, x: u32, y: u32, value: u16) {
222 let rotation = self.display_rotation;
223
224 let idx = match rotation {
225 DisplayRotation::Rotate0 | DisplayRotation::Rotate180 => {
226 ((y as usize) * D::WIDTH as usize) + (x as usize)
227 }
228 DisplayRotation::Rotate90 | DisplayRotation::Rotate270 => {
229 ((x as usize) * D::HEIGHT as usize) + (y as usize)
230 }
231 };
232
233 if let Some(color) = self.mode.buffer.as_mut().get_mut(idx) {
234 self.mode.min_x = self.mode.min_x.min(x as u16);
235 self.mode.max_x = self.mode.max_x.max(x as u16);
236 self.mode.min_y = self.mode.min_y.min(y as u16);
237 self.mode.max_y = self.mode.max_y.max(y as u16);
238
239 *color = value;
240 }
241 }
242}
243
244#[cfg(feature = "graphics")]
245use embedded_graphics_core::{
246 draw_target::DrawTarget,
247 geometry::Size,
248 geometry::{Dimensions, OriginDimensions},
249 pixelcolor::raw::RawU16,
250 pixelcolor::Rgb565,
251 prelude::RawData,
252 Pixel,
253};
254
255#[cfg(feature = "graphics")]
256impl<I, D> OriginDimensions for Gc9a01<I, D, BufferedGraphics<D>>
257where
258 I: WriteOnlyDataCommand,
259 D: DisplayDefinition,
260{
261 fn size(&self) -> Size {
262 let (w, h) = self.dimensions();
263 Size::new(w.into(), h.into())
264 }
265}
266
267#[cfg(feature = "graphics")]
268impl<I, D> DrawTarget for Gc9a01<I, D, BufferedGraphics<D>>
269where
270 I: WriteOnlyDataCommand,
271 D: DisplayDefinition,
272{
273 type Color = Rgb565;
275 type Error = DisplayError;
276
277 fn draw_iter<O>(&mut self, pixels: O) -> Result<(), Self::Error>
278 where
279 O: IntoIterator<Item = Pixel<Self::Color>>,
280 {
281 let bb = self.bounding_box();
282
283 pixels
284 .into_iter()
285 .filter(|&Pixel(pos, _color)| bb.contains(pos))
286 .for_each(|Pixel(pos, color)| {
287 let color: RawU16 = color.into();
288 let color: u16 = color.into_inner();
289 #[allow(clippy::cast_sign_loss)]
290 self.set_pixel(pos.x as u32, pos.y as u32, color);
291 });
292 Ok(())
293 }
294}