hobo_css/properties/
border.rs

1use crate::{append_property::AppendProperty, prelude::*, Property};
2
3crate::macros::easy_enum! {border-collapse separate collapse}
4crate::macros::easy_enum! {box-decoration-break slice clone}
5crate::macros::easy_enum! {outline-width medium thin thick [unit]}
6crate::macros::easy_enum! {outline-style none hidden dotted dashed solid double groove ridge inset outset}
7crate::macros::easy_enum! {border-image-slice fill [raw]} // TODO:
8crate::macros::easy_enum! {border-image-width auto [raw]} // TODO:
9crate::macros::easy_enum! {border-image-outset [raw]} // TODO:
10crate::macros::easy_enum! {border-image-repeat stretch repeat round space}
11crate::macros::easy_color! {outline-color}
12
13#[derive(Debug, PartialEq, Eq, Hash, Clone, PartialOrd, Ord)]
14pub enum BorderImageSource {
15	None,
16	Initial,
17	Inherit,
18	Unset,
19	Some(Vec<crate::Image>),
20}
21
22impl std::fmt::Display for BorderImageSource {
23	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
24		match self {
25			Self::None    => "border-image-source:none;".fmt(f),
26			Self::Initial => "border-image-source:initial;".fmt(f),
27			Self::Inherit => "border-image-source:inherit;".fmt(f),
28			Self::Unset   => "border-image-source:unset;".fmt(f),
29			Self::Some(images) => {
30				"border-image-source:".fmt(f)?;
31				if let Some((first, rest)) = images.split_first() {
32					write!(f, "{}", first)?;
33					for image in rest {
34						write!(f, ",{}", image)?;
35					}
36				}
37				";".fmt(f)
38			},
39		}
40	}
41}
42
43#[rustfmt::skip]
44#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy, strum::Display, PartialOrd, Ord)]
45pub enum BorderStyle {
46	#[strum(to_string = "none")] None,
47	#[strum(to_string = "hidden")] Hidden,
48	#[strum(to_string = "dotted")] Dotted,
49	#[strum(to_string = "dashed")] Dashed,
50	#[strum(to_string = "solid")] Solid,
51	#[strum(to_string = "double")] Double,
52	#[strum(to_string = "groove")] Groove,
53	#[strum(to_string = "ridge")] Ridge,
54	#[strum(to_string = "inset")] Inset,
55	#[strum(to_string = "outset")] Outset,
56	#[strum(to_string = "initial")] Initial,
57	#[strum(to_string = "inherit")] Inherit,
58	#[strum(to_string = "unset")] Unset,
59}
60
61#[derive(Debug, PartialEq, Eq, Hash, Clone, PartialOrd, Ord)]
62pub enum BorderWidth {
63	Medium,
64	Thin,
65	Thick,
66	Some(crate::Unit),
67	Initial,
68	Inherit,
69	Unset,
70}
71
72#[rustfmt::skip]
73impl std::fmt::Display for BorderWidth {
74	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
75		match self {
76			Self::Medium  => "medium".fmt(f),
77			Self::Thin    => "thin".fmt(f),
78			Self::Thick   => "thick".fmt(f),
79			Self::Some(x) => x.fmt(f),
80			Self::Initial => "initial".fmt(f),
81			Self::Inherit => "inherit".fmt(f),
82			Self::Unset   => "unset".fmt(f),
83		}
84	}
85}
86
87#[derive(Debug, PartialEq, Eq, Hash, Clone, Default, PartialOrd, Ord)]
88pub struct BoxShadowEffect {
89	pub inset: bool,
90	pub offset_x: Unit,
91	pub offset_y: Unit,
92	pub blur_radius: Unit,
93	pub spread_radius: Unit,
94	pub color: crate::Color,
95}
96
97impl std::fmt::Display for BoxShadowEffect {
98	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
99		if self.inset { "inset ".fmt(f)? }
100		write!(f, "{} {} {} {} {}", self.offset_x, self.offset_y, self.blur_radius, self.spread_radius, self.color)
101	}
102}
103
104impl AppendProperty for BoxShadowEffect {
105	fn append_property(self, props: &mut Vec<Property>) { BoxShadow::Some(vec![self]).append_property(props) }
106}
107
108#[derive(Debug, PartialEq, Eq, Hash, Clone, PartialOrd, Ord)]
109pub enum BoxShadow {
110	None,
111	Initial,
112	Inherit,
113	Unset,
114	Some(Vec<BoxShadowEffect>),
115}
116
117impl std::fmt::Display for BoxShadow {
118	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
119		match self {
120			Self::None    => "box-shadow:none;".fmt(f),
121			Self::Initial => "box-shadow:initial;".fmt(f),
122			Self::Inherit => "box-shadow:inherit;".fmt(f),
123			Self::Unset   => "box-shadow:unset;".fmt(f),
124			Self::Some(effects) => {
125				"box-shadow:".fmt(f)?;
126				if let Some((first, rest)) = effects.split_first() {
127					write!(f, "{}", first)?;
128					for effect in rest {
129						write!(f, ",{}", effect)?;
130					}
131				}
132				";".fmt(f)
133			},
134		}
135	}
136}
137
138#[rustfmt::skip]
139#[macro_export]
140#[doc(hidden)]
141macro_rules! __border_width {
142	($side:ident, medium)      => {$crate::paste::item!{$crate::Property::[<Border $side Width>]($crate::BorderWidth::Medium)}};
143	($side:ident, thin)        => {$crate::paste::item!{$crate::Property::[<Border $side Width>]($crate::BorderWidth::Thin)}};
144	($side:ident, thick)       => {$crate::paste::item!{$crate::Property::[<Border $side Width>]($crate::BorderWidth::Thick)}};
145	($side:ident, initial)     => {$crate::paste::item!{$crate::Property::[<Border $side Width>]($crate::BorderWidth::Initial)}};
146	($side:ident, inherit)     => {$crate::paste::item!{$crate::Property::[<Border $side Width>]($crate::BorderWidth::Inherit)}};
147	($side:ident, unset)       => {$crate::paste::item!{$crate::Property::[<Border $side Width>]($crate::BorderWidth::Unset)}};
148	($side:ident, $($val:tt)+) => {$crate::paste::item!{$crate::Property::[<Border $side Width>]($crate::BorderWidth::Some($crate::unit!($($val)+)))}};
149}
150
151#[macro_export] macro_rules! border_left_width {($($tt:tt)+)   => {$crate::__border_width!(Left, $($tt)+)}}
152#[macro_export] macro_rules! border_right_width {($($tt:tt)+)  => {$crate::__border_width!(Right, $($tt)+)}}
153#[macro_export] macro_rules! border_top_width {($($tt:tt)+)    => {$crate::__border_width!(Top, $($tt)+)}}
154#[macro_export] macro_rules! border_bottom_width {($($tt:tt)+) => {$crate::__border_width!(Bottom, $($tt)+)}}
155#[macro_export] macro_rules! border_width {($($tt:tt)+) => {
156	vec![
157		$crate::border_left_width!($($tt)+),
158		$crate::border_right_width!($($tt)+),
159		$crate::border_top_width!($($tt)+),
160		$crate::border_bottom_width!($($tt)+),
161	]
162}}
163
164#[rustfmt::skip]
165#[macro_export]
166#[doc(hidden)]
167macro_rules! __border_style {
168	($side:ident, none)    => {$crate::paste::item!{$crate::Property::[<Border $side Style>]($crate::BorderStyle::None)}};
169	($side:ident, hidden)  => {$crate::paste::item!{$crate::Property::[<Border $side Style>]($crate::BorderStyle::Hidden)}};
170	($side:ident, dotted)  => {$crate::paste::item!{$crate::Property::[<Border $side Style>]($crate::BorderStyle::Dotted)}};
171	($side:ident, dashed)  => {$crate::paste::item!{$crate::Property::[<Border $side Style>]($crate::BorderStyle::Dashed)}};
172	($side:ident, solid)   => {$crate::paste::item!{$crate::Property::[<Border $side Style>]($crate::BorderStyle::Solid)}};
173	($side:ident, double)  => {$crate::paste::item!{$crate::Property::[<Border $side Style>]($crate::BorderStyle::Double)}};
174	($side:ident, groove)  => {$crate::paste::item!{$crate::Property::[<Border $side Style>]($crate::BorderStyle::Groove)}};
175	($side:ident, ridge)   => {$crate::paste::item!{$crate::Property::[<Border $side Style>]($crate::BorderStyle::Ridge)}};
176	($side:ident, inset)   => {$crate::paste::item!{$crate::Property::[<Border $side Style>]($crate::BorderStyle::Inset)}};
177	($side:ident, outset)  => {$crate::paste::item!{$crate::Property::[<Border $side Style>]($crate::BorderStyle::Outset)}};
178	($side:ident, initial) => {$crate::paste::item!{$crate::Property::[<Border $side Style>]($crate::BorderStyle::Initial)}};
179	($side:ident, inherit) => {$crate::paste::item!{$crate::Property::[<Border $side Style>]($crate::BorderStyle::Inherit)}};
180	($side:ident, unset)   => {$crate::paste::item!{$crate::Property::[<Border $side Style>]($crate::BorderStyle::Unset)}};
181}
182
183#[macro_export] macro_rules! border_left_style {($($tt:tt)+)   => {$crate::__border_style!(Left, $($tt)+)}}
184#[macro_export] macro_rules! border_right_style {($($tt:tt)+)  => {$crate::__border_style!(Right, $($tt)+)}}
185#[macro_export] macro_rules! border_top_style {($($tt:tt)+)    => {$crate::__border_style!(Top, $($tt)+)}}
186#[macro_export] macro_rules! border_bottom_style {($($tt:tt)+) => {$crate::__border_style!(Bottom, $($tt)+)}}
187#[macro_export] macro_rules! border_style {($($tt:tt)+) => {
188	vec![
189		$crate::border_left_style!($($tt)+),
190		$crate::border_right_style!($($tt)+),
191		$crate::border_top_style!($($tt)+),
192		$crate::border_bottom_style!($($tt)+),
193	]
194}}
195
196crate::macros::easy_color! {border_left_color}
197crate::macros::easy_color! {border_right_color}
198crate::macros::easy_color! {border_top_color}
199crate::macros::easy_color! {border_bottom_color}
200#[macro_export] macro_rules! border_color {($($tt:tt)+) => {
201	vec![
202		$crate::border_left_color!($($tt)+),
203		$crate::border_right_color!($($tt)+),
204		$crate::border_top_color!($($tt)+),
205		$crate::border_bottom_color!($($tt)+),
206	]
207}}
208
209crate::macros::unit_value_macro! {border_top_left_radius BorderTopLeftRadius}
210crate::macros::unit_value_macro! {border_top_right_radius BorderTopRightRadius}
211crate::macros::unit_value_macro! {border_bottom_left_radius BorderBottomLeftRadius}
212crate::macros::unit_value_macro! {border_bottom_right_radius BorderBottomRightRadius}
213#[macro_export] macro_rules! border_radius {($($tt:tt)+) => {
214	vec![
215		$crate::border_top_left_radius!($($tt)+),
216		$crate::border_top_right_radius!($($tt)+),
217		$crate::border_bottom_left_radius!($($tt)+),
218		$crate::border_bottom_right_radius!($($tt)+),
219	]
220}}
221
222#[test]
223fn border_width_values() {
224	assert_eq!(__border_width!(Left, medium).to_string(), "border-left-width:medium;");
225	assert_eq!(__border_width!(Left, thin).to_string(), "border-left-width:thin;");
226	assert_eq!(__border_width!(Left, thick).to_string(), "border-left-width:thick;");
227	assert_eq!(__border_width!(Left, initial).to_string(), "border-left-width:initial;");
228	assert_eq!(__border_width!(Left, inherit).to_string(), "border-left-width:inherit;");
229	assert_eq!(__border_width!(Left, unset).to_string(), "border-left-width:unset;");
230
231	assert_eq!(__border_width!(Right, medium).to_string(), "border-right-width:medium;");
232	assert_eq!(__border_width!(Right, thin).to_string(), "border-right-width:thin;");
233	assert_eq!(__border_width!(Right, thick).to_string(), "border-right-width:thick;");
234	assert_eq!(__border_width!(Right, initial).to_string(), "border-right-width:initial;");
235	assert_eq!(__border_width!(Right, inherit).to_string(), "border-right-width:inherit;");
236	assert_eq!(__border_width!(Right, unset).to_string(), "border-right-width:unset;");
237
238	assert_eq!(__border_width!(Top, medium).to_string(), "border-top-width:medium;");
239	assert_eq!(__border_width!(Top, thin).to_string(), "border-top-width:thin;");
240	assert_eq!(__border_width!(Top, thick).to_string(), "border-top-width:thick;");
241	assert_eq!(__border_width!(Top, initial).to_string(), "border-top-width:initial;");
242	assert_eq!(__border_width!(Top, inherit).to_string(), "border-top-width:inherit;");
243	assert_eq!(__border_width!(Top, unset).to_string(), "border-top-width:unset;");
244
245	assert_eq!(__border_width!(Bottom, medium).to_string(), "border-bottom-width:medium;");
246	assert_eq!(__border_width!(Bottom, thin).to_string(), "border-bottom-width:thin;");
247	assert_eq!(__border_width!(Bottom, thick).to_string(), "border-bottom-width:thick;");
248	assert_eq!(__border_width!(Bottom, initial).to_string(), "border-bottom-width:initial;");
249	assert_eq!(__border_width!(Bottom, inherit).to_string(), "border-bottom-width:inherit;");
250	assert_eq!(__border_width!(Bottom, unset).to_string(), "border-bottom-width:unset;");
251}
252
253#[test]
254fn border_style_values() {
255	assert_eq!(__border_style!(Left, none).to_string(), "border-left-style:none;");
256	assert_eq!(__border_style!(Left, hidden).to_string(), "border-left-style:hidden;");
257	assert_eq!(__border_style!(Left, dotted).to_string(), "border-left-style:dotted;");
258	assert_eq!(__border_style!(Left, dashed).to_string(), "border-left-style:dashed;");
259	assert_eq!(__border_style!(Left, solid).to_string(), "border-left-style:solid;");
260	assert_eq!(__border_style!(Left, double).to_string(), "border-left-style:double;");
261	assert_eq!(__border_style!(Left, groove).to_string(), "border-left-style:groove;");
262	assert_eq!(__border_style!(Left, ridge).to_string(), "border-left-style:ridge;");
263	assert_eq!(__border_style!(Left, inset).to_string(), "border-left-style:inset;");
264	assert_eq!(__border_style!(Left, outset).to_string(), "border-left-style:outset;");
265	assert_eq!(__border_style!(Left, initial).to_string(), "border-left-style:initial;");
266	assert_eq!(__border_style!(Left, inherit).to_string(), "border-left-style:inherit;");
267	assert_eq!(__border_style!(Left, unset).to_string(), "border-left-style:unset;");
268
269	assert_eq!(__border_style!(Right, none).to_string(), "border-right-style:none;");
270	assert_eq!(__border_style!(Right, hidden).to_string(), "border-right-style:hidden;");
271	assert_eq!(__border_style!(Right, dotted).to_string(), "border-right-style:dotted;");
272	assert_eq!(__border_style!(Right, dashed).to_string(), "border-right-style:dashed;");
273	assert_eq!(__border_style!(Right, solid).to_string(), "border-right-style:solid;");
274	assert_eq!(__border_style!(Right, double).to_string(), "border-right-style:double;");
275	assert_eq!(__border_style!(Right, groove).to_string(), "border-right-style:groove;");
276	assert_eq!(__border_style!(Right, ridge).to_string(), "border-right-style:ridge;");
277	assert_eq!(__border_style!(Right, inset).to_string(), "border-right-style:inset;");
278	assert_eq!(__border_style!(Right, outset).to_string(), "border-right-style:outset;");
279	assert_eq!(__border_style!(Right, initial).to_string(), "border-right-style:initial;");
280	assert_eq!(__border_style!(Right, inherit).to_string(), "border-right-style:inherit;");
281	assert_eq!(__border_style!(Right, unset).to_string(), "border-right-style:unset;");
282
283	assert_eq!(__border_style!(Top, none).to_string(), "border-top-style:none;");
284	assert_eq!(__border_style!(Top, hidden).to_string(), "border-top-style:hidden;");
285	assert_eq!(__border_style!(Top, dotted).to_string(), "border-top-style:dotted;");
286	assert_eq!(__border_style!(Top, dashed).to_string(), "border-top-style:dashed;");
287	assert_eq!(__border_style!(Top, solid).to_string(), "border-top-style:solid;");
288	assert_eq!(__border_style!(Top, double).to_string(), "border-top-style:double;");
289	assert_eq!(__border_style!(Top, groove).to_string(), "border-top-style:groove;");
290	assert_eq!(__border_style!(Top, ridge).to_string(), "border-top-style:ridge;");
291	assert_eq!(__border_style!(Top, inset).to_string(), "border-top-style:inset;");
292	assert_eq!(__border_style!(Top, outset).to_string(), "border-top-style:outset;");
293	assert_eq!(__border_style!(Top, initial).to_string(), "border-top-style:initial;");
294	assert_eq!(__border_style!(Top, inherit).to_string(), "border-top-style:inherit;");
295	assert_eq!(__border_style!(Top, unset).to_string(), "border-top-style:unset;");
296
297	assert_eq!(__border_style!(Bottom, none).to_string(), "border-bottom-style:none;");
298	assert_eq!(__border_style!(Bottom, hidden).to_string(), "border-bottom-style:hidden;");
299	assert_eq!(__border_style!(Bottom, dotted).to_string(), "border-bottom-style:dotted;");
300	assert_eq!(__border_style!(Bottom, dashed).to_string(), "border-bottom-style:dashed;");
301	assert_eq!(__border_style!(Bottom, solid).to_string(), "border-bottom-style:solid;");
302	assert_eq!(__border_style!(Bottom, double).to_string(), "border-bottom-style:double;");
303	assert_eq!(__border_style!(Bottom, groove).to_string(), "border-bottom-style:groove;");
304	assert_eq!(__border_style!(Bottom, ridge).to_string(), "border-bottom-style:ridge;");
305	assert_eq!(__border_style!(Bottom, inset).to_string(), "border-bottom-style:inset;");
306	assert_eq!(__border_style!(Bottom, outset).to_string(), "border-bottom-style:outset;");
307	assert_eq!(__border_style!(Bottom, initial).to_string(), "border-bottom-style:initial;");
308	assert_eq!(__border_style!(Bottom, inherit).to_string(), "border-bottom-style:inherit;");
309	assert_eq!(__border_style!(Bottom, unset).to_string(), "border-bottom-style:unset;");
310}