endbasic_std/gfx/lcd/
mod.rs1use crate::console::{RGB, SizeInPixels};
19use std::convert::TryFrom;
20use std::io;
21
22mod buffered;
23pub mod fonts;
24
25pub use buffered::BufferedLcd;
26
27pub trait AsByteSlice {
29 fn as_slice(&self) -> &[u8];
31}
32
33#[derive(Clone, Copy)]
35pub struct RGB565Pixel(pub [u8; 2]);
36
37impl AsByteSlice for RGB565Pixel {
38 fn as_slice(&self) -> &[u8] {
39 &self.0
40 }
41}
42
43pub trait Lcd {
45 type Pixel: AsByteSlice + Copy;
47
48 fn info(&self) -> (LcdSize, usize);
50
51 fn encode(&self, rgb: RGB) -> Self::Pixel;
53
54 fn set_data(&mut self, x1y1: LcdXY, x2y2: LcdXY, data: &[u8]) -> io::Result<()>;
57}
58
59#[derive(Clone, Copy)]
61#[cfg_attr(test, derive(Debug, PartialEq))]
62pub struct LcdXY {
63 pub x: usize,
65
66 pub y: usize,
68}
69
70#[derive(Clone, Copy)]
72#[cfg_attr(test, derive(Debug, PartialEq))]
73pub struct LcdSize {
74 pub width: usize,
76
77 pub height: usize,
79}
80
81impl LcdSize {
82 fn between(x1y1: LcdXY, x2y2: LcdXY) -> Self {
84 debug_assert!(x2y2.x >= x1y1.x);
85 debug_assert!(x2y2.y >= x1y1.y);
86 Self { width: x2y2.x - x1y1.x + 1, height: x2y2.y - x1y1.y + 1 }
87 }
88
89 fn new_buffer(&self, stride: usize) -> Vec<u8> {
92 Vec::with_capacity(self.width * self.height * stride)
93 }
94}
95
96impl From<LcdSize> for SizeInPixels {
97 fn from(value: LcdSize) -> Self {
98 Self::new(
99 u16::try_from(value.width).expect("Must fit"),
100 u16::try_from(value.height).expect("Must fit"),
101 )
102 }
103}
104
105pub fn to_xy_size(x1y1: LcdXY, x2y2: LcdXY) -> (LcdXY, LcdSize) {
107 let x1 = std::cmp::min(x1y1.x, x2y2.x);
108 let y1 = std::cmp::min(x1y1.y, x2y2.y);
109
110 let x2 = std::cmp::max(x1y1.x, x2y2.x);
111 let y2 = std::cmp::max(x1y1.y, x2y2.y);
112
113 (LcdXY { x: x1, y: y1 }, LcdSize { width: x2 + 1 - x1, height: y2 + 1 - y1 })
114}
115
116#[cfg(test)]
117mod tests {
118 use super::*;
119
120 fn xy(x: usize, y: usize) -> LcdXY {
122 LcdXY { x, y }
123 }
124
125 fn size(width: usize, height: usize) -> LcdSize {
127 LcdSize { width, height }
128 }
129
130 #[test]
131 fn test_lcdsize_between_one_pixel() {
132 assert_eq!(size(1, 1), LcdSize::between(xy(15, 16), xy(15, 16)));
133 }
134
135 #[test]
136 fn test_lcdsize_between_rect() {
137 assert_eq!(size(4, 5), LcdSize::between(xy(10, 25), xy(13, 29)));
138 }
139
140 #[test]
141 fn test_lcdsize_new_buffer() {
142 let buffer = size(10, 20).new_buffer(3);
143 assert_eq!(10 * 20 * 3, buffer.capacity());
144 }
145
146 #[test]
147 fn test_to_xy_size_one_pixel() {
148 assert_eq!(
149 (LcdXY { x: 10, y: 20 }, LcdSize { width: 1, height: 1 }),
150 to_xy_size(xy(10, 20), xy(10, 20))
151 );
152 }
153
154 #[test]
155 fn test_to_xy_size_rect() {
156 assert_eq!(
157 (LcdXY { x: 10, y: 20 }, LcdSize { width: 5, height: 7 }),
158 to_xy_size(xy(10, 20), xy(14, 26))
159 );
160 }
161}