zest_widget/widget/
line.rs1use super::Widget;
11use core::marker::PhantomData;
12use embedded_graphics::{pixelcolor::PixelColor, prelude::*, primitives::Rectangle};
13use zest_core::{Constraints, Length, RenderError, Renderer, TouchPhase};
14use zest_theme::Theme;
15
16pub struct Line<'a, C: PixelColor, M: Clone> {
18 rect: Rectangle,
19 points: &'a [Point],
20 color: Option<C>,
21 line_width: u32,
22 absolute: bool,
25 width: Length,
26 height: Length,
27 _phantom: PhantomData<M>,
28}
29
30impl<'a, C: PixelColor, M: Clone> Line<'a, C, M> {
31 pub fn new(points: &'a [Point]) -> Self {
34 Self {
35 rect: Rectangle::zero(),
36 points,
37 color: None,
38 line_width: 1,
39 absolute: false,
40 width: Length::Fill,
41 height: Length::Fill,
42 _phantom: PhantomData,
43 }
44 }
45
46 #[must_use]
48 pub fn color(mut self, color: C) -> Self {
49 self.color = Some(color);
50 self
51 }
52
53 #[must_use]
55 pub fn width_px(mut self, width: u32) -> Self {
56 self.line_width = width;
57 self
58 }
59
60 #[must_use]
63 pub fn absolute(mut self) -> Self {
64 self.absolute = true;
65 self
66 }
67
68 #[must_use]
70 pub fn width(mut self, width: impl Into<Length>) -> Self {
71 self.width = width.into();
72 self
73 }
74
75 #[must_use]
77 pub fn height(mut self, height: impl Into<Length>) -> Self {
78 self.height = height.into();
79 self
80 }
81}
82
83impl<'a, C: PixelColor, M: Clone> Widget<C, M> for Line<'a, C, M> {
84 fn measure(&mut self, constraints: Constraints) -> Size {
85 let w = self
86 .width
87 .resolve(constraints.max.width, constraints.max.width);
88 let h = self
89 .height
90 .resolve(constraints.max.height, constraints.max.height);
91 constraints.clamp(Size::new(w, h))
92 }
93
94 fn preferred_size(&self) -> (Length, Length) {
95 (self.width, self.height)
96 }
97
98 fn arrange(&mut self, rect: Rectangle) {
99 self.rect = rect;
100 }
101
102 fn rect(&self) -> Rectangle {
103 self.rect
104 }
105
106 fn handle_touch(&mut self, _point: Point, _phase: TouchPhase) -> Option<M> {
107 None
108 }
109
110 fn draw<'t>(
111 &self,
112 renderer: &mut dyn Renderer<C>,
113 theme: &Theme<'t, C>,
114 ) -> Result<(), RenderError> {
115 if self.points.len() < 2 {
116 return Ok(());
117 }
118 let color = self.color.unwrap_or(theme.background.on_base);
119 let offset = if self.absolute {
120 Point::zero()
121 } else {
122 self.rect.top_left
123 };
124 for pair in self.points.windows(2) {
125 renderer.stroke_line(pair[0] + offset, pair[1] + offset, color, self.line_width)?;
126 }
127 Ok(())
128 }
129}