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 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 |limits| {
111 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 = 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> {}