1use crate::style::LineStyle;
4use embedded_graphics::prelude::*;
5
6#[derive(Debug, Clone)]
8pub struct AxisStyle<C: PixelColor> {
9 pub axis_line: LineStyle<C>,
11 pub major_ticks: TickStyle<C>,
13 pub minor_ticks: TickStyle<C>,
15 pub grid_lines: Option<LineStyle<C>>,
17 pub labels: LabelStyle<C>,
19 pub label_offset: u32,
21}
22
23#[derive(Debug, Clone)]
25pub struct TickStyle<C: PixelColor> {
26 pub line: LineStyle<C>,
28 pub length: u32,
30 pub visible: bool,
32}
33
34#[derive(Debug, Clone)]
36pub struct LabelStyle<C: PixelColor> {
37 pub color: C,
39 pub font_size: u32,
41 pub visible: bool,
43 pub alignment: TextAlignment,
45 pub rotation: u16,
47}
48
49#[derive(Debug, Clone, Copy, PartialEq, Eq)]
51pub enum TextAlignment {
52 Start,
54 Center,
56 End,
58}
59
60impl<C: PixelColor> AxisStyle<C>
61where
62 C: From<embedded_graphics::pixelcolor::Rgb565>,
63{
64 pub fn new() -> Self {
66 Self {
67 axis_line: LineStyle::solid(embedded_graphics::pixelcolor::Rgb565::RED.into()).width(3),
68 major_ticks: TickStyle::new(embedded_graphics::pixelcolor::Rgb565::RED.into(), 10),
69 minor_ticks: TickStyle::new(embedded_graphics::pixelcolor::Rgb565::BLUE.into(), 5),
70 grid_lines: None,
71 labels: LabelStyle::new(embedded_graphics::pixelcolor::Rgb565::BLACK.into()),
72 label_offset: 8,
73 }
74 }
75
76 pub fn with_axis_line(mut self, style: LineStyle<C>) -> Self {
78 self.axis_line = style;
79 self
80 }
81
82 pub fn with_major_ticks(mut self, style: TickStyle<C>) -> Self {
84 self.major_ticks = style;
85 self
86 }
87
88 pub fn with_minor_ticks(mut self, style: TickStyle<C>) -> Self {
90 self.minor_ticks = style;
91 self
92 }
93
94 pub fn with_grid_lines(mut self, style: LineStyle<C>) -> Self {
96 self.grid_lines = Some(style);
97 self
98 }
99
100 pub fn without_grid_lines(mut self) -> Self {
102 self.grid_lines = None;
103 self
104 }
105
106 pub fn with_labels(mut self, style: LabelStyle<C>) -> Self {
108 self.labels = style;
109 self
110 }
111
112 pub fn with_label_offset(mut self, offset: u32) -> Self {
114 self.label_offset = offset;
115 self
116 }
117
118 pub fn minimal() -> Self {
120 Self {
121 axis_line: LineStyle::solid(embedded_graphics::pixelcolor::Rgb565::BLACK.into()),
122 major_ticks: TickStyle::new(embedded_graphics::pixelcolor::Rgb565::BLACK.into(), 3),
123 minor_ticks: TickStyle::new(embedded_graphics::pixelcolor::Rgb565::BLACK.into(), 1)
124 .hidden(),
125 grid_lines: None,
126 labels: LabelStyle::new(embedded_graphics::pixelcolor::Rgb565::BLACK.into())
127 .with_font_size(8),
128 label_offset: 4,
129 }
130 }
131
132 pub fn professional() -> Self {
134 Self {
135 axis_line: LineStyle::solid(embedded_graphics::pixelcolor::Rgb565::BLACK.into()),
136 major_ticks: TickStyle::new(embedded_graphics::pixelcolor::Rgb565::BLACK.into(), 8),
137 minor_ticks: TickStyle::new(
138 embedded_graphics::pixelcolor::Rgb565::new(16, 32, 16).into(), 4, )
141 .with_width(1), grid_lines: Some(LineStyle::solid(
143 embedded_graphics::pixelcolor::Rgb565::new(25, 50, 25).into(),
144 )),
145 labels: LabelStyle::new(embedded_graphics::pixelcolor::Rgb565::BLACK.into()),
146 label_offset: 10,
147 }
148 }
149}
150
151impl<C: PixelColor> TickStyle<C> {
152 pub fn new(color: C, length: u32) -> Self {
154 Self {
155 line: LineStyle::solid(color),
156 length,
157 visible: true,
158 }
159 }
160
161 pub fn with_color(mut self, color: C) -> Self {
163 self.line = self.line.color(color);
164 self
165 }
166
167 pub fn with_width(mut self, width: u32) -> Self {
169 self.line = self.line.width(width);
170 self
171 }
172
173 pub fn with_length(mut self, length: u32) -> Self {
175 self.length = length;
176 self
177 }
178
179 pub fn hidden(mut self) -> Self {
181 self.visible = false;
182 self
183 }
184
185 pub fn visible(mut self) -> Self {
187 self.visible = true;
188 self
189 }
190}
191
192impl<C: PixelColor> LabelStyle<C> {
193 pub fn new(color: C) -> Self {
195 Self {
196 color,
197 font_size: 12,
198 visible: true,
199 alignment: TextAlignment::Center,
200 rotation: 0,
201 }
202 }
203
204 pub fn with_color(mut self, color: C) -> Self {
206 self.color = color;
207 self
208 }
209
210 pub fn with_font_size(mut self, size: u32) -> Self {
212 self.font_size = size;
213 self
214 }
215
216 pub fn with_alignment(mut self, alignment: TextAlignment) -> Self {
218 self.alignment = alignment;
219 self
220 }
221
222 pub fn with_rotation(mut self, degrees: u16) -> Self {
224 self.rotation = match degrees {
225 0..=45 => 0,
226 46..=135 => 90,
227 136..=225 => 180,
228 226..=315 => 270,
229 _ => 0,
230 };
231 self
232 }
233
234 pub fn hidden(mut self) -> Self {
236 self.visible = false;
237 self
238 }
239
240 pub fn visible(mut self) -> Self {
242 self.visible = true;
243 self
244 }
245}
246
247impl<C: PixelColor> Default for AxisStyle<C>
248where
249 C: From<embedded_graphics::pixelcolor::Rgb565>,
250{
251 fn default() -> Self {
252 Self::new()
253 }
254}
255
256impl<C: PixelColor> Default for TickStyle<C>
257where
258 C: From<embedded_graphics::pixelcolor::Rgb565>,
259{
260 fn default() -> Self {
261 Self::new(embedded_graphics::pixelcolor::Rgb565::BLACK.into(), 4)
262 }
263}
264
265impl<C: PixelColor> Default for LabelStyle<C>
266where
267 C: From<embedded_graphics::pixelcolor::Rgb565>,
268{
269 fn default() -> Self {
270 Self::new(embedded_graphics::pixelcolor::Rgb565::BLACK.into())
271 }
272}
273
274impl Default for TextAlignment {
275 fn default() -> Self {
276 Self::Center
277 }
278}
279
280#[cfg(test)]
281mod tests {
282 use super::*;
283 use embedded_graphics::pixelcolor::Rgb565;
284
285 #[test]
286 fn test_axis_style_creation() {
287 let style: AxisStyle<Rgb565> = AxisStyle::new();
288 assert!(style.major_ticks.visible);
289 assert!(style.minor_ticks.visible);
290 assert!(style.grid_lines.is_none());
291 }
292
293 #[test]
294 fn test_tick_style_builder() {
295 let style = TickStyle::new(Rgb565::RED, 5).with_width(2).with_length(8);
296
297 assert_eq!(style.length, 8);
298 assert!(style.visible);
299 }
300
301 #[test]
302 fn test_label_style_builder() {
303 let style = LabelStyle::new(Rgb565::BLUE)
304 .with_font_size(14)
305 .with_alignment(TextAlignment::Start)
306 .with_rotation(90);
307
308 assert_eq!(style.font_size, 14);
309 assert_eq!(style.alignment, TextAlignment::Start);
310 assert_eq!(style.rotation, 90);
311 }
312
313 #[test]
314 fn test_professional_style() {
315 let style: AxisStyle<Rgb565> = AxisStyle::professional();
316 assert!(style.grid_lines.is_some());
317 assert_eq!(style.label_offset, 10);
318 }
319
320 #[test]
321 fn test_minimal_style() {
322 let style: AxisStyle<Rgb565> = AxisStyle::minimal();
323 assert!(!style.minor_ticks.visible);
324 assert_eq!(style.label_offset, 4);
325 }
326}