mini_oled/screen/
canvas.rs1use crate::screen::fast_mul;
19
20use crate::error::MiniOledError;
21
22use crate::screen::properties::{DisplayProperties, DisplayRotation};
23
24pub struct Canvas<const N: usize, const W: u32, const H: u32, const O: u8> {
39 buffer: [u8; N],
40 dirty_area_min: (u32, u32),
41 dirty_area_max: (u32, u32),
42 display_properties: DisplayProperties<W, H, O>,
43}
44
45impl<const N: usize, const W: u32, const H: u32, const O: u8> Canvas<N, W, H, O> {
46 pub(crate) fn new(display_properties: DisplayProperties<W, H, O>) -> Self {
47 Canvas {
48 buffer: [0; N],
49 dirty_area_max: (0, 0),
50 dirty_area_min: display_properties.get_display_size(),
51 display_properties,
52 }
53 }
54
55 pub(crate) fn get_column_offset(&self) -> u8 {
56 self.display_properties.get_column_offset()
57 }
58
59 pub(crate) const fn get_display_size(&self) -> (u32, u32) {
60 self.display_properties.get_display_size()
61 }
62
63 pub(crate) fn get_rotation(&self) -> &DisplayRotation {
64 self.display_properties.get_rotation()
65 }
66
67 pub(crate) fn set_rotation(&mut self, display_rotation: DisplayRotation) {
68 self.display_properties.set_rotation(display_rotation);
69 }
70
71 pub fn get_buffer(&self) -> &[u8; N] {
73 &self.buffer
74 }
75
76 pub fn get_mut_buffer(&mut self) -> &mut [u8; N] {
78 &mut self.buffer
79 }
80
81 pub(crate) fn get_dirty_area(&self) -> ((u32, u32), (u32, u32)) {
82 (self.dirty_area_min, self.dirty_area_max)
83 }
84
85 pub(crate) fn force_full_dirty_area(&mut self) {
86 self.dirty_area_min = (0, 0);
87 self.dirty_area_max = (W - 1, H - 1);
88 }
89
90 pub(crate) fn reset_dirty_area(&mut self) {
91 self.dirty_area_min = self.display_properties.get_display_size();
92 self.dirty_area_max = (0, 0);
93 }
94
95 #[inline]
96 pub fn set_pixel(&mut self, x: u32, y: u32, pixel_status: bool) {
104 let (physical_width, physical_height) = self.display_properties.get_display_size();
105 let display_rotation = self.display_properties.get_rotation();
106
107 let (calculated_width_for_rotation, calculated_height_for_rotation) = match display_rotation
108 {
109 DisplayRotation::Rotate0 | DisplayRotation::Rotate180 => {
110 (physical_width, physical_height)
111 }
112 DisplayRotation::Rotate90 | DisplayRotation::Rotate270 => {
113 (physical_height, physical_width)
114 }
115 };
116
117 if x >= calculated_width_for_rotation || y >= calculated_height_for_rotation {
118 return;
119 }
120
121 if x < self.dirty_area_min.0 {
122 self.dirty_area_min.0 = x;
123 }
124 if y < self.dirty_area_min.1 {
125 self.dirty_area_min.1 = y;
126 }
127 if x > self.dirty_area_max.0 {
128 self.dirty_area_max.0 = x;
129 }
130 if y > self.dirty_area_max.1 {
131 self.dirty_area_max.1 = y;
132 }
133
134 let (idx, bit_mask) = match *display_rotation {
135 DisplayRotation::Rotate0 | DisplayRotation::Rotate180 => {
136 let idx = fast_mul!((y >> 3), W) + x; let bit = 1 << (y & 7); (idx as usize, bit)
139 }
140 DisplayRotation::Rotate90 | DisplayRotation::Rotate270 => {
141 let idx = fast_mul!((x >> 3), W) + y; let bit = 1 << (x & 7); (idx as usize, bit)
144 }
145 };
146 if idx < N {
154 let pixel_status_mask = (-(pixel_status as i8)) as u8;
155 self.buffer[idx] = (self.buffer[idx] & !bit_mask) | (pixel_status_mask & bit_mask);
156 }
157 }
158}
159#[cfg(feature = "embedded-graphics-core")]
160use embedded_graphics_core::{
161 Pixel,
162 pixelcolor::BinaryColor,
163 prelude::{Dimensions, DrawTarget, OriginDimensions, Size},
164};
165
166#[cfg(feature = "embedded-graphics-core")]
167impl<const N: usize, const W: u32, const H: u32, const O: u8> DrawTarget for Canvas<N, W, H, O> {
168 type Color = BinaryColor;
169
170 type Error = MiniOledError;
171
172 fn draw_iter<I>(&mut self, pixels: I) -> Result<(), Self::Error>
173 where
174 I: IntoIterator<Item = embedded_graphics_core::Pixel<Self::Color>>,
175 {
176 let bb = self.bounding_box();
177
178 pixels
179 .into_iter()
180 .filter(|Pixel(pos, _color)| bb.contains(*pos))
181 .for_each(|Pixel(pos, color)| {
182 self.set_pixel(pos.x as u32, pos.y as u32, color.is_on())
183 });
184
185 Ok(())
186 }
187}
188
189#[cfg(feature = "embedded-graphics-core")]
190impl<const N: usize, const W: u32, const H: u32, const O: u8> OriginDimensions
191 for Canvas<N, W, H, O>
192{
193 fn size(&self) -> Size {
194 let (width, height) = self.display_properties.get_display_size();
195
196 Size::new(width, height)
197 }
198}