hal_core/
framebuffer.rs

1use core::ops::{Deref, DerefMut};
2use maitake_sync::blocking;
3
4#[cfg(feature = "embedded-graphics-core")]
5#[doc(cfg(feature = "embedded-graphics-core"))]
6mod embedded_graphics;
7#[cfg(feature = "embedded-graphics-core")]
8#[doc(cfg(feature = "embedded-graphics-core"))]
9pub use self::embedded_graphics::*;
10
11pub trait Draw {
12    /// Return the width of the framebuffer in pixels.
13    fn width(&self) -> usize;
14
15    /// Returns the height of the framebuffer in pixels.
16    fn height(&self) -> usize;
17
18    /// Set the pixel at position (`x`, `y`) to the provided `color`.
19    fn set_pixel(&mut self, x: usize, y: usize, color: RgbColor) -> &mut Self;
20
21    /// Draw a horizontal line of length `len` at height `y`.
22    ///
23    /// By default, this method calls `set_pixel` in a loop. This _works_, but
24    /// implementations can almost certainly provide a more optimal
25    /// implementation, and are thus encouraged to override this method.
26    fn line_horiz(&mut self, y: usize, len: usize, color: RgbColor) -> &mut Self {
27        for x in 0..len {
28            self.set_pixel(x, y, color);
29        }
30        self
31    }
32
33    /// Draw a vertical line of length `len` at column `y`.
34    ///
35    /// By default, this method calls `set_pixel` in a loop. This _works_, but
36    /// implementations can almost certainly provide a more optimal
37    /// implementation, and are thus encouraged to override this method.
38    fn line_vert(&mut self, x: usize, len: usize, color: RgbColor) -> &mut Self {
39        for y in 0..len {
40            self.set_pixel(x, y, color);
41        }
42        self
43    }
44
45    #[inline]
46    fn fill_row(&mut self, y: usize, color: RgbColor) -> &mut Self {
47        self.line_horiz(y, self.width(), color)
48    }
49
50    #[inline]
51    fn fill_col(&mut self, x: usize, color: RgbColor) -> &mut Self {
52        self.line_vert(x, self.height(), color)
53    }
54
55    /// Fill the entire framebuffer with the provided color.
56    ///
57    /// By default, this method calls `set_pixel` in a loop. This _works_, but
58    /// implementations can almost certainly provide a more optimal
59    /// implementation, and are thus encouraged to override this method.
60    fn fill(&mut self, color: RgbColor) -> &mut Self {
61        for y in 0..self.height() {
62            self.fill_row(y, color);
63        }
64        self
65    }
66
67    /// Clear the entire framebuffer.
68    ///
69    /// By default, this method calls `set_pixel` in a loop. This _works_, but
70    /// implementations can almost certainly provide a more optimal
71    /// implementation, and are thus encouraged to override this method.
72    fn clear(&mut self) -> &mut Self {
73        self.fill(RgbColor::BLACK);
74        self
75    }
76
77    fn scroll_vert(&mut self, px: isize) -> &mut Self;
78
79    #[cfg(feature = "embedded-graphics-core")]
80    #[doc(cfg(feature = "embedded-graphics-core"))]
81    fn into_draw_target(self) -> DrawTarget<Self>
82    where
83        Self: Sized,
84    {
85        DrawTarget::new(self)
86    }
87
88    #[cfg(feature = "embedded-graphics-core")]
89    #[doc(cfg(feature = "embedded-graphics-core"))]
90    fn as_draw_target(&mut self) -> DrawTarget<&mut Self>
91    where
92        Self: Sized,
93    {
94        DrawTarget::new(self)
95    }
96}
97
98#[derive(Copy, Clone, Debug, Eq, PartialEq)]
99pub struct RgbColor {
100    pub red: u8,
101    pub green: u8,
102    pub blue: u8,
103}
104
105impl RgbColor {
106    pub const BLACK: Self = Self {
107        red: 0,
108        green: 0,
109        blue: 0,
110    };
111    pub const RED: Self = Self {
112        red: 255,
113        green: 0,
114        blue: 0,
115    };
116    pub const GREEN: Self = Self {
117        red: 0,
118        green: 255,
119        blue: 0,
120    };
121    pub const BLUE: Self = Self {
122        red: 0,
123        green: 0,
124        blue: 255,
125    };
126}
127
128macro_rules! deref_draw_body {
129    () => {
130        #[inline]
131        fn width(&self) -> usize {
132            self.deref().width()
133        }
134
135        #[inline]
136        fn height(&self) -> usize {
137            self.deref().height()
138        }
139
140        #[inline]
141        fn set_pixel(&mut self, x: usize, y: usize, color: RgbColor) -> &mut Self {
142            self.deref_mut().set_pixel(x, y, color);
143            self
144        }
145
146        #[inline]
147        fn line_horiz(&mut self, y: usize, len: usize, color: RgbColor) -> &mut Self {
148            self.deref_mut().line_horiz(y, len, color);
149            self
150        }
151
152        #[inline]
153        fn line_vert(&mut self, x: usize, len: usize, color: RgbColor) -> &mut Self {
154            self.deref_mut().line_vert(x, len, color);
155            self
156        }
157
158        #[inline]
159        fn fill_row(&mut self, y: usize, color: RgbColor) -> &mut Self {
160            self.deref_mut().fill_row(y, color);
161            self
162        }
163
164        #[inline]
165        fn fill_col(&mut self, x: usize, color: RgbColor) -> &mut Self {
166            self.deref_mut().fill_col(x, color);
167            self
168        }
169
170        #[inline]
171        fn scroll_vert(&mut self, px: isize) -> &mut Self {
172            self.deref_mut().scroll_vert(px);
173            self
174        }
175
176        #[inline]
177        fn fill(&mut self, color: RgbColor) -> &mut Self {
178            self.deref_mut().fill(color);
179            self
180        }
181
182        #[inline]
183        fn clear(&mut self) -> &mut Self {
184            self.deref_mut().clear();
185            self
186        }
187    };
188}
189
190impl<D, L> Draw for blocking::MutexGuard<'_, D, L>
191where
192    D: Draw,
193    L: blocking::RawMutex,
194{
195    deref_draw_body! {}
196}
197
198impl<D> Draw for &'_ mut D
199where
200    D: Draw,
201{
202    deref_draw_body! {}
203}