freya_core/values/
border.rs1use std::fmt;
2
3use freya_engine::prelude::Color;
4use torin::scaled::Scaled;
5
6use super::Fill;
7use crate::parsing::{
8 ExtSplit,
9 Parse,
10 ParseError,
11};
12
13#[derive(Default, Clone, Debug, PartialEq)]
14pub struct Border {
15 pub fill: Fill,
16 pub width: BorderWidth,
17 pub alignment: BorderAlignment,
18}
19
20impl Border {
21 #[inline]
22 pub fn is_visible(&self) -> bool {
23 !(self.width.top == 0.0
24 && self.width.left == 0.0
25 && self.width.bottom == 0.0
26 && self.width.right == 0.0)
27 && self.fill != Fill::Color(Color::TRANSPARENT)
28 }
29}
30
31#[derive(Default, Clone, Copy, Debug, PartialEq)]
32pub struct BorderWidth {
33 pub top: f32,
34 pub right: f32,
35 pub bottom: f32,
36 pub left: f32,
37}
38
39impl Scaled for BorderWidth {
40 fn scale(&mut self, scale_factor: f32) {
41 self.top *= scale_factor;
42 self.left *= scale_factor;
43 self.bottom *= scale_factor;
44 self.right *= scale_factor;
45 }
46}
47
48impl fmt::Display for BorderWidth {
49 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
50 write!(
51 f,
52 "{} {} {} {}",
53 self.top, self.right, self.bottom, self.left,
54 )
55 }
56}
57
58#[derive(Default, Clone, Copy, Debug, PartialEq)]
59pub enum BorderAlignment {
60 #[default]
61 Inner,
62 Outer,
63 Center,
64}
65
66impl Parse for BorderAlignment {
67 fn parse(value: &str) -> Result<Self, ParseError> {
68 Ok(match value {
69 "inner" => BorderAlignment::Inner,
70 "outer" => BorderAlignment::Outer,
71 "center" => BorderAlignment::Center,
72 _ => BorderAlignment::default(),
73 })
74 }
75}
76
77impl fmt::Display for BorderAlignment {
78 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
79 f.write_str(match self {
80 BorderAlignment::Inner => "inner",
81 BorderAlignment::Outer => "outer",
82 BorderAlignment::Center => "center",
83 })
84 }
85}
86
87impl Parse for Border {
88 fn parse(value: &str) -> Result<Self, ParseError> {
89 if value == "none" {
90 return Ok(Self::default());
91 }
92
93 let mut border_values = value.split_ascii_whitespace_excluding_group('(', ')');
94
95 Ok(match border_values.clone().count() {
96 3 => {
98 let width = border_values
99 .next()
100 .ok_or(ParseError)?
101 .parse::<f32>()
102 .map_err(|_| ParseError)?;
103
104 Border {
105 width: BorderWidth {
106 top: width,
107 left: width,
108 bottom: width,
109 right: width,
110 },
111 alignment: BorderAlignment::parse(border_values.next().ok_or(ParseError)?)?,
112 fill: Fill::parse(&border_values.collect::<Vec<&str>>().join(" "))
113 .map_err(|_| ParseError)?,
114 }
115 }
116
117 4 => {
119 let vertical_width = border_values
120 .next()
121 .ok_or(ParseError)?
122 .parse::<f32>()
123 .map_err(|_| ParseError)?;
124 let horizontal_width = border_values
125 .next()
126 .ok_or(ParseError)?
127 .parse::<f32>()
128 .map_err(|_| ParseError)?;
129
130 Border {
131 width: BorderWidth {
132 top: vertical_width,
133 left: horizontal_width,
134 bottom: vertical_width,
135 right: horizontal_width,
136 },
137 alignment: BorderAlignment::parse(border_values.next().ok_or(ParseError)?)?,
138 fill: Fill::parse(&border_values.collect::<Vec<&str>>().join(" "))
139 .map_err(|_| ParseError)?,
140 }
141 }
142 5 => {
144 let top_width = border_values
145 .next()
146 .ok_or(ParseError)?
147 .parse::<f32>()
148 .map_err(|_| ParseError)?;
149 let horizontal_width = border_values
150 .next()
151 .ok_or(ParseError)?
152 .parse::<f32>()
153 .map_err(|_| ParseError)?;
154 let bottom_width = border_values
155 .next()
156 .ok_or(ParseError)?
157 .parse::<f32>()
158 .map_err(|_| ParseError)?;
159
160 Border {
161 width: BorderWidth {
162 top: top_width,
163 left: horizontal_width,
164 bottom: bottom_width,
165 right: horizontal_width,
166 },
167 alignment: BorderAlignment::parse(border_values.next().ok_or(ParseError)?)?,
168 fill: Fill::parse(&border_values.collect::<Vec<&str>>().join(" "))
169 .map_err(|_| ParseError)?,
170 }
171 }
172 6 => Border {
174 width: BorderWidth {
175 top: border_values
176 .next()
177 .ok_or(ParseError)?
178 .parse::<f32>()
179 .map_err(|_| ParseError)?,
180 right: border_values
181 .next()
182 .ok_or(ParseError)?
183 .parse::<f32>()
184 .map_err(|_| ParseError)?,
185 bottom: border_values
186 .next()
187 .ok_or(ParseError)?
188 .parse::<f32>()
189 .map_err(|_| ParseError)?,
190 left: border_values
191 .next()
192 .ok_or(ParseError)?
193 .parse::<f32>()
194 .map_err(|_| ParseError)?,
195 },
196 alignment: BorderAlignment::parse(border_values.next().ok_or(ParseError)?)?,
197 fill: Fill::parse(&border_values.collect::<Vec<&str>>().join(" "))
198 .map_err(|_| ParseError)?,
199 },
200 _ => return Err(ParseError),
201 })
202 }
203}
204
205impl fmt::Display for Border {
206 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
207 write!(f, "{} {} {}", self.width, self.alignment, self.fill,)
208 }
209}
210
211impl Scaled for Border {
212 fn scale(&mut self, scale_factor: f32) {
213 self.width.scale(scale_factor);
214 }
215}