use crate::buffer_len;
use crate::color::Color;
use embedded_graphics_core::prelude::*;
#[derive(Clone, Copy, Default)]
pub enum DisplayRotation {
#[default]
Rotate0,
Rotate90,
Rotate180,
Rotate270,
}
#[derive(Clone, Copy)]
pub enum DisplayColorRendering {
Positive,
Negative,
}
pub trait Display: DrawTarget<Color = Color> {
fn clear_buffer(&mut self, background_color: Color) {
for elem in self.get_mut_buffer().iter_mut() {
*elem = background_color.get_byte_value();
}
}
fn buffer(&self) -> &[u8];
fn get_mut_buffer(&mut self) -> &mut [u8];
fn set_rotation(&mut self, rotation: DisplayRotation);
fn rotation(&self) -> DisplayRotation;
fn draw_helper(
&mut self,
width: u32,
height: u32,
pixel: Pixel<Color>,
) -> Result<(), Self::Error> {
let rotation = self.rotation();
let buffer = self.get_mut_buffer();
let Pixel(point, color) = pixel;
if outside_display(point, width, height, rotation) {
return Ok(());
}
let (index, bit) = find_position(point.x as u32, point.y as u32, width, height, rotation);
let index = index as usize;
match color {
Color::Dark => {
buffer[index] &= !bit;
}
Color::Green => {
buffer[index] |= bit;
}
}
Ok(())
}
}
pub struct VarDisplay<'a> {
width: u32,
height: u32,
rotation: DisplayRotation,
buffer: &'a mut [u8], }
impl<'a> VarDisplay<'a> {
pub fn new(width: u32, height: u32, buffer: &'a mut [u8]) -> VarDisplay<'a> {
let len = buffer.len() as u32;
assert!(buffer_len(width as usize, height as usize) >= len as usize);
VarDisplay {
width,
height,
rotation: DisplayRotation::default(),
buffer,
}
}
}
impl<'a> DrawTarget for VarDisplay<'a> {
type Color = Color;
type Error = core::convert::Infallible;
fn draw_iter<I>(&mut self, pixels: I) -> Result<(), Self::Error>
where
I: IntoIterator<Item = Pixel<Self::Color>>,
{
for pixel in pixels {
self.draw_helper(self.width, self.height, pixel)?;
}
Ok(())
}
}
impl<'a> OriginDimensions for VarDisplay<'a> {
fn size(&self) -> Size {
Size::new(self.width, self.height)
}
}
impl<'a> Display for VarDisplay<'a> {
fn buffer(&self) -> &[u8] {
self.buffer
}
fn get_mut_buffer(&mut self) -> &mut [u8] {
self.buffer
}
fn set_rotation(&mut self, rotation: DisplayRotation) {
self.rotation = rotation;
}
fn rotation(&self) -> DisplayRotation {
self.rotation
}
}
fn outside_display(p: Point, width: u32, height: u32, rotation: DisplayRotation) -> bool {
if p.x < 0 || p.y < 0 {
return true;
}
let (x, y) = (p.x as u32, p.y as u32);
match rotation {
DisplayRotation::Rotate0 | DisplayRotation::Rotate180 => {
if x >= width || y >= height {
return true;
}
}
DisplayRotation::Rotate90 | DisplayRotation::Rotate270 => {
if y >= width || x >= height {
return true;
}
}
}
false
}
fn find_rotation(x: u32, y: u32, width: u32, height: u32, rotation: DisplayRotation) -> (u32, u32) {
let nx;
let ny;
match rotation {
DisplayRotation::Rotate0 => {
nx = x;
ny = y;
}
DisplayRotation::Rotate90 => {
nx = width - 1 - y;
ny = x;
}
DisplayRotation::Rotate180 => {
nx = width - 1 - x;
ny = height - 1 - y;
}
DisplayRotation::Rotate270 => {
nx = y;
ny = height - 1 - x;
}
}
(nx, ny)
}
#[rustfmt::skip]
fn find_position(x: u32, y: u32, width: u32, height: u32, rotation: DisplayRotation) -> (u32, u8) {
let (nx, ny) = find_rotation(x, y, width, height, rotation);
(
nx / 8 + ((width + 7) / 8) * ny,
0x80 >> (nx % 8),
)
}