embedded_ui/
render.rs

1use core::{fmt::Display, marker::PhantomData};
2
3use embedded_graphics::{
4    geometry::Point,
5    image::{Image, ImageRaw},
6    iterator::raw::RawDataSlice,
7    mono_font::MonoTextStyle,
8    pixelcolor::{raw::BigEndian, BinaryColor, PixelColor},
9    primitives::{
10        Arc, Circle, Line, PrimitiveStyle, PrimitiveStyleBuilder, RoundedRectangle, StyledDrawable,
11    },
12    text::renderer::CharacterStyle,
13    Pixel,
14};
15use embedded_graphics_core::Drawable;
16use embedded_graphics_core::{draw_target::DrawTarget, primitives::Rectangle};
17use embedded_text::TextBox;
18
19use crate::{
20    block::Block,
21    color::UiColor,
22    size::{Bounds, Size},
23};
24
25pub trait Renderer {
26    type Color: UiColor + Copy;
27
28    // Renderer info
29    fn clear(&mut self);
30
31    fn z_index(&self) -> i32 {
32        0
33    }
34
35    #[inline]
36    fn with_z_index(&mut self, z_index: i32, draw: impl Fn(&mut Self)) {
37        let _z_index = z_index;
38        draw(self)
39    }
40
41    #[inline]
42    fn relative_z_index(&mut self, z_index_offset: i32, draw: impl Fn(&mut Self)) {
43        self.with_z_index(self.z_index() + z_index_offset, draw);
44    }
45
46    #[inline]
47    fn under(&mut self, draw: impl Fn(&mut Self)) {
48        self.relative_z_index(-1, draw);
49    }
50
51    #[inline]
52    fn above(&mut self, draw: impl Fn(&mut Self)) {
53        self.relative_z_index(1, draw);
54    }
55
56    fn topmost(&mut self, draw: impl Fn(&mut Self)) {
57        self.with_z_index(i32::MAX, draw);
58    }
59
60    // Primitives //
61    fn pixel(&mut self, point: Point, color: Self::Color);
62    fn line(&mut self, start: Point, end: Point, color: Self::Color, width: u32);
63
64    // TODO: Own Arc, Circle and Sector structs might be needed
65    fn arc(&mut self, arc: Arc, style: PrimitiveStyle<Self::Color>);
66    fn circle(&mut self, circle: Circle, style: PrimitiveStyle<Self::Color>);
67
68    // High-level primitives //
69    fn block(&mut self, block: Block<Self::Color>);
70
71    fn mono_text<'a>(&mut self, text: TextBox<'a, MonoTextStyle<'a, Self::Color>>);
72    fn image<'a>(&mut self, image: Image<'a, ImageRaw<'a, Self::Color>>)
73    where
74        RawDataSlice<'a, <Self::Color as PixelColor>::Raw, BigEndian>:
75            IntoIterator<Item = <Self::Color as PixelColor>::Raw>;
76}
77
78pub struct NullRenderer;
79
80// impl<'a> TextRenderer<'a, MonoTextStyle<'a, BinaryColor>> for NullRenderer {
81//     type Color = BinaryColor;
82
83//     fn text(&mut self, _text: TextBox<'a, MonoTextStyle<'a, BinaryColor>>) {}
84// }
85
86impl Renderer for NullRenderer {
87    type Color = BinaryColor;
88
89    fn clear(&mut self) {}
90
91    fn pixel(&mut self, _point: Point, _color: Self::Color) {}
92    fn line(&mut self, _from: Point, _to: Point, _color: Self::Color, _width: u32) {}
93    fn arc(&mut self, _arc: Arc, _style: PrimitiveStyle<Self::Color>) {}
94    fn circle(&mut self, _circle: Circle, _style: PrimitiveStyle<Self::Color>) {}
95
96    fn block(&mut self, _block: Block<Self::Color>) {}
97
98    fn mono_text<'a>(&mut self, _text: TextBox<'a, MonoTextStyle<'a, Self::Color>>) {}
99    fn image<'a>(&mut self, _image: Image<'a, ImageRaw<'a, Self::Color>>)
100    where
101        RawDataSlice<'a, <Self::Color as PixelColor>::Raw, BigEndian>:
102            IntoIterator<Item = <Self::Color as PixelColor>::Raw>,
103    {
104    }
105}
106
107impl<D, C: UiColor> Renderer for D
108where
109    D: DrawTarget<Color = C>,
110    D::Error: core::fmt::Debug,
111{
112    type Color = C;
113
114    fn clear(&mut self) {
115        self.clear(Self::Color::default_background()).unwrap()
116    }
117
118    fn pixel(&mut self, point: Point, color: Self::Color) {
119        Pixel(point, color).draw(self).unwrap();
120    }
121
122    fn line(&mut self, start: Point, end: Point, color: Self::Color, width: u32) {
123        Line::new(start, end)
124            .draw_styled(
125                &PrimitiveStyleBuilder::new().stroke_width(width).stroke_color(color).build(),
126                self,
127            )
128            .unwrap();
129    }
130
131    fn arc(&mut self, arc: Arc, style: PrimitiveStyle<Self::Color>) {
132        arc.draw_styled(&style, self).unwrap();
133    }
134
135    fn circle(&mut self, circle: Circle, style: PrimitiveStyle<Self::Color>) {
136        circle.draw_styled(&style, self).unwrap();
137    }
138
139    fn block(&mut self, block: Block<Self::Color>)
140    where
141        Self: Sized,
142    {
143        RoundedRectangle::new(
144            block.rect,
145            block.border.radius.resolve_for_size(block.rect.size.into()).into(),
146        )
147        .draw_styled(
148            &PrimitiveStyleBuilder::new()
149                .fill_color(block.background)
150                .stroke_color(block.border.color)
151                .stroke_width(block.border.width)
152                .build(),
153            self,
154        )
155        .unwrap();
156    }
157
158    fn mono_text(&mut self, text: TextBox<'_, MonoTextStyle<'_, Self::Color>>) {
159        text.draw(self).unwrap();
160    }
161
162    fn image<'a>(&mut self, image: Image<'a, ImageRaw<'a, Self::Color>>)
163    where
164        RawDataSlice<'a, <Self::Color as PixelColor>::Raw, BigEndian>:
165            IntoIterator<Item = <Self::Color as PixelColor>::Raw>,
166    {
167        image.draw(self).unwrap();
168    }
169}