embedded_ui/kit/
divider.rs

1use embedded_graphics::geometry::Point;
2
3use crate::align::Axis;
4use crate::color::UiColor;
5use crate::el::El;
6use crate::layout::{Layout, LayoutNode, Viewport};
7use crate::size::{Length, Size};
8use crate::widget::Widget;
9use crate::{event::Event, padding::Padding, render::Renderer};
10
11pub struct Divider<R>
12where
13    R: Renderer,
14{
15    axis: Axis,
16    thickness: u32,
17    color: R::Color,
18    padding: Padding,
19}
20
21impl<R> Divider<R>
22where
23    R: Renderer,
24{
25    pub fn new(axis: Axis) -> Self {
26        let (padding_main, padding_anti) = axis.canon(0, 1);
27        Self {
28            axis,
29            thickness: 1,
30            color: R::Color::default_foreground(),
31            padding: Padding::new_axis(padding_anti, padding_main),
32        }
33    }
34
35    pub fn vertical() -> Self {
36        Self::new(Axis::Y)
37    }
38
39    pub fn horizontal() -> Self {
40        Self::new(Axis::X)
41    }
42
43    pub fn thickness(mut self, thickness: u32) -> Self {
44        self.thickness = thickness;
45        self
46    }
47
48    pub fn color(mut self, color: R::Color) -> Self {
49        self.color = color;
50        self
51    }
52
53    /// Add a little padding on sides
54    pub fn inset(mut self) -> Self {
55        let (padding_main, _padding_anti) =
56            self.axis.canon(self.padding.total_x(), self.padding.total_y());
57        let (main_axis, anti_axis) = self.axis.canon(padding_main, 5);
58        self.padding = self.padding + Padding::new_axis(anti_axis, main_axis);
59        self
60    }
61
62    pub fn padding(mut self, padding: impl Into<Padding>) -> Self {
63        self.padding = padding.into();
64        self
65    }
66}
67
68impl<Message, R, E, S> Widget<Message, R, E, S> for Divider<R>
69where
70    R: Renderer,
71    E: Event,
72{
73    fn id(&self) -> Option<crate::el::ElId> {
74        None
75    }
76
77    fn tree_ids(&self) -> alloc::vec::Vec<crate::el::ElId> {
78        vec![]
79    }
80
81    fn size(&self) -> crate::size::Size<crate::size::Length> {
82        let (main_axis, anti_axis) = self.axis.canon(
83            Length::Fill,
84            Length::Fixed(self.thickness + self.padding.total_axis(self.axis.invert())),
85        );
86        Size::new(main_axis, anti_axis)
87    }
88
89    fn layout(
90        &self,
91        _ctx: &mut crate::ui::UiCtx<Message>,
92        _state: &mut crate::state::StateNode,
93        _styler: &S,
94        limits: &crate::layout::Limits,
95        viewport: &Viewport,
96    ) -> crate::layout::LayoutNode {
97        let (main_axis, anti_axis) = self.axis.canon(
98            Length::Fill,
99            Length::Fixed(self.thickness + self.padding.total_axis(self.axis.invert())),
100        );
101        let size = Size::new(main_axis, anti_axis);
102
103        Layout::sized(
104            limits,
105            size,
106            crate::layout::Position::Relative,
107            viewport,
108            // self.padding,
109            // Padding::zero(),
110            |limits| {
111                // let (main_axis, anti_axis) =
112                //     self.axis.canon(limits.max().axis(self.axis), self.thickness);
113                // LayoutNode::new(Size::new(main_axis, anti_axis))
114                // LayoutNode::new(limits.max())
115                limits.resolve_size(size.width, size.height, Size::zero())
116            },
117        )
118    }
119
120    fn draw(
121        &self,
122        _ctx: &mut crate::ui::UiCtx<Message>,
123        _state: &mut crate::state::StateNode,
124        renderer: &mut R,
125        _styler: &S,
126        layout: crate::layout::Layout,
127    ) {
128        let bounds = layout.bounds();
129
130        let (main_axis_size, anti_axis_size) =
131            self.axis.canon(bounds.size.width, bounds.size.height);
132        // let start = bounds.position + self.padding.top_left();
133        let start = Point::new(bounds.position.x, bounds.position.y + anti_axis_size as i32 / 2);
134        let (main_axis_start, anti_axis_start) = self.axis.canon(start.x, start.y);
135        let end = self.axis.canon(main_axis_start + main_axis_size as i32, anti_axis_start);
136        let end = Point::new(end.0, end.1);
137
138        renderer.line(start, end, self.color, self.thickness)
139    }
140}
141
142impl<'a, Message, R, E, S> From<Divider<R>> for El<'a, Message, R, E, S>
143where
144    Message: 'a,
145    R: Renderer + 'a,
146    E: Event + 'a,
147    S: 'a,
148{
149    fn from(value: Divider<R>) -> Self {
150        El::new(value)
151    }
152}
153
154impl<R: Renderer> Clone for Divider<R> {
155    fn clone(&self) -> Self {
156        Self {
157            axis: self.axis,
158            thickness: self.thickness,
159            color: self.color,
160            padding: self.padding,
161        }
162    }
163}
164impl<R: Renderer> Copy for Divider<R> {}