st7789_driver/
graphics.rs

1use embedded_graphics_core::pixelcolor::Rgb565;
2use embedded_graphics_core::prelude::{DrawTarget, IntoStorage, Point, Size};
3use embedded_graphics_core::{
4    pixelcolor::raw::{RawData, RawU16},
5    primitives::Rectangle,
6};
7use embedded_graphics_core::{prelude::OriginDimensions, Pixel};
8
9use embedded_hal::digital::v2::OutputPin;
10
11use crate::{Error, Orientation, ST7789};
12use display_interface::WriteOnlyDataCommand;
13
14impl<DI, RST, BL, PinE> ST7789<DI, RST, BL>
15where
16    DI: WriteOnlyDataCommand,
17    RST: OutputPin<Error = PinE>,
18    BL: OutputPin<Error = PinE>,
19{
20    /// Returns the bounding box for the entire framebuffer.
21    fn framebuffer_bounding_box(&self) -> Rectangle {
22        let size = match self.orientation {
23            Orientation::Portrait | Orientation::PortraitSwapped => Size::new(240, 320),
24            Orientation::Landscape | Orientation::LandscapeSwapped => Size::new(320, 240),
25        };
26
27        Rectangle::new(Point::zero(), size)
28    }
29}
30
31impl<DI, RST, BL, PinE> DrawTarget for ST7789<DI, RST, BL>
32where
33    DI: WriteOnlyDataCommand,
34    RST: OutputPin<Error = PinE>,
35    BL: OutputPin<Error = PinE>,
36{
37    type Error = Error<PinE>;
38    type Color = Rgb565;
39
40    #[cfg(not(feature = "batch"))]
41    fn draw_iter<I>(&mut self, pixels: I) -> Result<(), Self::Error>
42    where
43        I: IntoIterator<Item = Pixel<Self::Color>>,
44    {
45        for pixel in pixels {
46            let color = RawU16::from(pixel.1).into_inner();
47            let x = pixel.0.x as u16;
48            let y = pixel.0.y as u16;
49
50            self.set_pixel(x, y, color)?;
51        }
52
53        Ok(())
54    }
55
56    #[cfg(feature = "batch")]
57    fn draw_iter<T>(&mut self, item: T) -> Result<(), Self::Error>
58    where
59        T: IntoIterator<Item = Pixel<Rgb565>>,
60    {
61        use crate::batch::DrawBatch;
62
63        self.draw_batch(item)
64    }
65
66    fn fill_contiguous<I>(&mut self, area: &Rectangle, colors: I) -> Result<(), Self::Error>
67    where
68        I: IntoIterator<Item = Self::Color>,
69    {
70        if let Some(bottom_right) = area.bottom_right() {
71            let mut count = 0u32;
72            let max = area.size.width * area.size.height;
73
74            let mut colors = colors
75                .into_iter()
76                .take_while(|_| {
77                    count += 1;
78                    count <= max
79                })
80                .map(|color| RawU16::from(color).into_inner());
81
82            let sx = area.top_left.x as u16;
83            let sy = area.top_left.y as u16;
84            let ex = bottom_right.x as u16;
85            let ey = bottom_right.y as u16;
86            self.set_pixels(sx, sy, ex, ey, &mut colors)
87        } else {
88            // nothing to draw
89            Ok(())
90        }
91    }
92
93    fn fill_solid(&mut self, area: &Rectangle, color: Self::Color) -> Result<(), Self::Error> {
94        let area = area.intersection(&self.framebuffer_bounding_box());
95
96        if let Some(bottom_right) = area.bottom_right() {
97            let mut count = 0u32;
98            let max = area.size.width * area.size.height;
99
100            let mut colors = core::iter::repeat(color.into_storage()).take_while(|_| {
101                count += 1;
102                count <= max
103            });
104
105            let sx = area.top_left.x as u16;
106            let sy = area.top_left.y as u16;
107            let ex = bottom_right.x as u16;
108            let ey = bottom_right.y as u16;
109            self.set_pixels(sx, sy, ex, ey, &mut colors)
110        } else {
111            // nothing to draw
112            Ok(())
113        }
114    }
115
116    fn clear(&mut self, color: Rgb565) -> Result<(), Self::Error>
117    where
118        Self: Sized,
119    {
120        let color16 = RawU16::from(color).into_inner();
121        const DIM1: u16 = 240;
122        const DIM2: u16 = 320;
123        let colors = (0..(DIM1 as u32 * DIM2 as u32)).map(|_| color16); // blank entire HW RAM contents
124
125        match self.orientation {
126            Orientation::Portrait | Orientation::PortraitSwapped => {
127                self.set_pixels(0, 0, DIM1 - 1, DIM2 - 1, colors)
128            }
129            Orientation::Landscape | Orientation::LandscapeSwapped => {
130                self.set_pixels(0, 0, DIM2 - 1, DIM1 - 1, colors)
131            }
132        }
133    }
134}
135
136impl<DI, RST, BL, PinE> OriginDimensions for ST7789<DI, RST, BL>
137where
138    DI: WriteOnlyDataCommand,
139    RST: OutputPin<Error = PinE>,
140    BL: OutputPin<Error = PinE>,
141{
142    fn size(&self) -> Size {
143        Size::new(self.size_x.into(), self.size_y.into()) // visible area, not RAM-pixel size
144    }
145}