1use crate::{color::Color, unit::*, StyleUpdater};
2use derive_rich::Rich;
3
4#[derive(Rich, Clone, Debug, PartialEq, Default)]
17pub struct Border {
18 #[rich(write(rename = left), write(style = compose))]
19 pub left: Side,
20 #[rich(write(rename = top), write(style = compose))]
21 pub top: Side,
22 #[rich(write(rename = right), write(style = compose))]
23 pub right: Side,
24 #[rich(write(rename = bottom), write(style = compose))]
25 pub bottom: Side,
26 #[rich(write(rename = top_left), write(option, rename = try_top_left))]
27 pub top_left: Option<Radius>,
28 #[rich(write(rename = top_right), write(option, rename = try_top_right))]
29 pub top_right: Option<Radius>,
30 #[rich(write(rename = bottom_left), write(option, rename = try_bottom_left))]
31 pub bottom_left: Option<Radius>,
32 #[rich(write(rename = bottom_right), write(option, rename = try_bottom_right))]
33 pub bottom_right: Option<Radius>,
34}
35
36impl StyleUpdater for Border {
37 fn update_style(self, style: crate::Style) -> crate::Style {
38 style
39 .try_insert("border-left-color", self.left.color)
41 .try_insert("border-left-width", self.left.width)
42 .try_insert("border-left-style", self.left.style)
43 .try_insert("border-top-color", self.top.color)
45 .try_insert("border-top-width", self.top.width)
46 .try_insert("border-top-style", self.top.style)
47 .try_insert("border-right-color", self.right.color)
49 .try_insert("border-right-width", self.right.width)
50 .try_insert("border-right-style", self.right.style)
51 .try_insert("border-bottom-color", self.bottom.color)
53 .try_insert("border-bottom-width", self.bottom.width)
54 .try_insert("border-bottom-style", self.bottom.style)
55 .try_insert("border-top-left-radius", self.top_left)
57 .try_insert("border-top-right-radius", self.top_right)
58 .try_insert("border-bottom-left-radius", self.bottom_left)
59 .try_insert("border-bottom-right-radius", self.bottom_right)
60 }
61}
62
63impl<T: Into<Color>> From<T> for Border {
64 fn from(source: T) -> Self {
65 Self::default().color(source.into())
66 }
67}
68
69impl From<Option<Border>> for Border {
70 fn from(source: Option<Border>) -> Self {
71 match source {
72 Some(border) => border,
73 None => Border::default().none(),
74 }
75 }
76}
77
78impl From<Radius> for Border {
79 fn from(source: Radius) -> Self {
80 Self::default().radius(source)
81 }
82}
83
84macro_rules! sides_style_shortcut_functions {
85 ( $( $fn:ident() $(,)? )* ) => {
86 $(
87 pub fn $fn(self) -> Self {
88 self.all_side(|side| side.$fn())
89 }
90 )*
91 }
92}
93
94impl Border {
95 pub fn all_side(self, value: impl Fn(Side) -> Side + Clone) -> Self {
96 self.and_left(value.clone())
97 .and_top(value.clone())
98 .and_right(value.clone())
99 .and_bottom(value)
100 }
101
102 pub fn style(self, style: impl Into<BorderStyle>) -> Self {
103 let style = style.into();
104 self.all_side(|side| side.style(style))
105 }
106
107 pub fn width(self, width: impl Into<Width>) -> Self {
108 let width = width.into();
109 self.all_side(|side| side.width(width.clone()))
110 }
111
112 pub fn color(self, color: impl Into<Color>) -> Self {
113 let color = color.into();
114 self.all_side(|side| side.color(color))
115 }
116
117 pub fn transparent(self) -> Self {
118 self.color(Color::Transparent)
119 }
120
121 pub fn radius(self, rad: impl Into<Radius>) -> Self {
122 let rad = rad.into();
123 self.top_left(rad.clone())
124 .top_right(rad.clone())
125 .bottom_left(rad.clone())
126 .bottom_right(rad)
127 }
128
129 pub fn top_radius(self, rad: impl Into<Radius>) -> Self {
130 let rad = rad.into();
131 self.top_left(rad.clone()).top_right(rad.clone())
132 }
133
134 pub fn right_radius(self, rad: impl Into<Radius>) -> Self {
135 let rad = rad.into();
136 self.bottom_right(rad.clone()).top_right(rad.clone())
137 }
138
139 pub fn bottom_radius(self, rad: impl Into<Radius>) -> Self {
140 let rad = rad.into();
141 self.bottom_right(rad.clone()).bottom_left(rad.clone())
142 }
143
144 pub fn left_radius(self, rad: impl Into<Radius>) -> Self {
145 let rad = rad.into();
146 self.bottom_left(rad.clone()).top_left(rad.clone())
147 }
148
149 sides_style_shortcut_functions! {
150 none(), hidden(), dotted(), dashed(), solid(), double(),
151 groove(), ridge(), inset(), outset(),
152 }
153}
154
155#[derive(Rich, Clone, Debug, PartialEq, From, Default)]
156pub struct Side {
157 #[rich(write(rename = style), write(option, rename = try_style), value_fns = {
158 none = BorderStyle::None,
159 hidden = BorderStyle::Hidden,
160 dotted = BorderStyle::Dotted,
161 dashed = BorderStyle::Dashed,
162 solid = BorderStyle::Solid,
163 double = BorderStyle::Double,
164 groove = BorderStyle::Groove,
165 ridge = BorderStyle::Ridge,
166 inset = BorderStyle::Inset,
167 outset = BorderStyle::Outset,
168 initial_style = BorderStyle::Initial,
169 inherit_style = BorderStyle::Inherit,
170 })]
171 pub style: Option<BorderStyle>,
172 #[rich(write(rename = width), write(option, rename = try_width), value_fns = {
173 thick = Width::Thick,
174 thin = Width::Thin,
175 medium = Width::Medium,
176 initial_width = Width::Initial,
177 inherit_width = Width::Inherit,
178 })]
179 pub width: Option<Width>,
180 #[rich(write(rename = color), write(option, rename = try_color))]
181 pub color: Option<Color>,
182}
183
184#[derive(Clone, Copy, Debug, PartialEq, Display, From)]
185pub enum BorderStyle {
186 #[display(fmt = "none")]
187 None,
188 #[display(fmt = "hidden")]
189 Hidden,
190 #[display(fmt = "dotted")]
191 Dotted,
192 #[display(fmt = "dashed")]
193 Dashed,
194 #[display(fmt = "solid")]
195 Solid,
196 #[display(fmt = "double")]
197 Double,
198 #[display(fmt = "groove")]
199 Groove,
200 #[display(fmt = "ridge")]
201 Ridge,
202 #[display(fmt = "inset")]
203 Inset,
204 #[display(fmt = "outset")]
205 Outset,
206 #[display(fmt = "initial")]
207 Initial,
208 #[display(fmt = "inherit")]
209 Inherit,
210}
211
212#[derive(Clone, Debug, PartialEq, Display, From)]
213pub enum Width {
214 Length(Length),
215 #[display(fmt = "thin")]
216 Thin,
217 #[display(fmt = "medium")]
218 Medium,
219 #[display(fmt = "thick")]
220 Thick,
221 #[display(fmt = "initial")]
222 Initial,
223 #[display(fmt = "inherit")]
224 Inherit,
225}
226
227#[derive(Clone, Debug, PartialEq, Display, From)]
228pub enum Radius {
229 #[from]
230 Length(Length),
231 #[from(forward)]
232 Percent(Percent),
233 #[display(fmt = "initial")]
234 Initial,
235 #[display(fmt = "inherit")]
236 Inherit,
237}