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 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 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 fn arc(&mut self, arc: Arc, style: PrimitiveStyle<Self::Color>);
66 fn circle(&mut self, circle: Circle, style: PrimitiveStyle<Self::Color>);
67
68 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
80impl 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}