1use crate::core::ToXml;
6
7#[derive(Clone, Debug, PartialEq, Eq)]
9pub struct RgbColor {
10 pub r: u8,
11 pub g: u8,
12 pub b: u8,
13}
14
15impl RgbColor {
16 pub fn new(r: u8, g: u8, b: u8) -> Self {
18 Self { r, g, b }
19 }
20
21 pub fn from_hex(hex: &str) -> Option<Self> {
23 let hex = hex.trim_start_matches('#');
24 if hex.len() != 6 {
25 return None;
26 }
27 let r = u8::from_str_radix(&hex[0..2], 16).ok()?;
28 let g = u8::from_str_radix(&hex[2..4], 16).ok()?;
29 let b = u8::from_str_radix(&hex[4..6], 16).ok()?;
30 Some(Self { r, g, b })
31 }
32
33 pub fn to_hex(&self) -> String {
35 format!("{:02X}{:02X}{:02X}", self.r, self.g, self.b)
36 }
37
38 pub fn black() -> Self {
40 Self::new(0, 0, 0)
41 }
42 pub fn white() -> Self {
43 Self::new(255, 255, 255)
44 }
45 pub fn red() -> Self {
46 Self::new(255, 0, 0)
47 }
48 pub fn green() -> Self {
49 Self::new(0, 255, 0)
50 }
51 pub fn blue() -> Self {
52 Self::new(0, 0, 255)
53 }
54}
55
56impl ToXml for RgbColor {
57 fn to_xml(&self) -> String {
58 format!(r#"<a:srgbClr val="{}"/>"#, self.to_hex())
59 }
60}
61
62impl Default for RgbColor {
63 fn default() -> Self {
64 Self::black()
65 }
66}
67
68#[derive(Clone, Debug, PartialEq, Eq)]
70pub enum SchemeColor {
71 Accent1,
72 Accent2,
73 Accent3,
74 Accent4,
75 Accent5,
76 Accent6,
77 Dark1,
78 Dark2,
79 Light1,
80 Light2,
81 Hyperlink,
82 FollowedHyperlink,
83 Background1,
84 Background2,
85 Text1,
86 Text2,
87}
88
89impl SchemeColor {
90 pub fn as_str(&self) -> &'static str {
91 match self {
92 SchemeColor::Accent1 => "accent1",
93 SchemeColor::Accent2 => "accent2",
94 SchemeColor::Accent3 => "accent3",
95 SchemeColor::Accent4 => "accent4",
96 SchemeColor::Accent5 => "accent5",
97 SchemeColor::Accent6 => "accent6",
98 SchemeColor::Dark1 => "dk1",
99 SchemeColor::Dark2 => "dk2",
100 SchemeColor::Light1 => "lt1",
101 SchemeColor::Light2 => "lt2",
102 SchemeColor::Hyperlink => "hlink",
103 SchemeColor::FollowedHyperlink => "folHlink",
104 SchemeColor::Background1 => "bg1",
105 SchemeColor::Background2 => "bg2",
106 SchemeColor::Text1 => "tx1",
107 SchemeColor::Text2 => "tx2",
108 }
109 }
110}
111
112impl ToXml for SchemeColor {
113 fn to_xml(&self) -> String {
114 format!(r#"<a:schemeClr val="{}"/>"#, self.as_str())
115 }
116}
117
118#[derive(Clone, Debug, PartialEq)]
120pub enum Color {
121 Rgb(RgbColor),
122 Scheme(SchemeColor),
123}
124
125impl Color {
126 pub fn rgb(r: u8, g: u8, b: u8) -> Self {
128 Color::Rgb(RgbColor::new(r, g, b))
129 }
130
131 pub fn from_hex(hex: &str) -> Option<Self> {
133 RgbColor::from_hex(hex).map(Color::Rgb)
134 }
135
136 pub fn scheme(color: SchemeColor) -> Self {
138 Color::Scheme(color)
139 }
140}
141
142impl ToXml for Color {
143 fn to_xml(&self) -> String {
144 match self {
145 Color::Rgb(rgb) => rgb.to_xml(),
146 Color::Scheme(scheme) => scheme.to_xml(),
147 }
148 }
149}
150
151impl Default for Color {
152 fn default() -> Self {
153 Color::Rgb(RgbColor::black())
154 }
155}
156
157#[cfg(test)]
158mod tests {
159 use super::*;
160
161 #[test]
162 fn test_rgb_from_hex() {
163 let color = RgbColor::from_hex("FF0000").unwrap();
164 assert_eq!(color.r, 255);
165 assert_eq!(color.g, 0);
166 assert_eq!(color.b, 0);
167
168 let color = RgbColor::from_hex("#00FF00").unwrap();
169 assert_eq!(color.to_hex(), "00FF00");
170 }
171
172 #[test]
173 fn test_rgb_to_xml() {
174 let color = RgbColor::new(255, 0, 0);
175 assert_eq!(color.to_xml(), r#"<a:srgbClr val="FF0000"/>"#);
176 }
177
178 #[test]
179 fn test_scheme_color() {
180 let color = SchemeColor::Accent1;
181 assert_eq!(color.to_xml(), r#"<a:schemeClr val="accent1"/>"#);
182 }
183
184 #[test]
185 fn test_color_enum() {
186 let rgb = Color::rgb(255, 0, 0);
187 assert_eq!(rgb.to_xml(), r#"<a:srgbClr val="FF0000"/>"#);
188
189 let scheme = Color::scheme(SchemeColor::Dark1);
190 assert_eq!(scheme.to_xml(), r#"<a:schemeClr val="dk1"/>"#);
191 }
192
193 #[test]
194 fn test_common_colors() {
195 assert_eq!(RgbColor::black().to_hex(), "000000");
196 assert_eq!(RgbColor::white().to_hex(), "FFFFFF");
197 assert_eq!(RgbColor::red().to_hex(), "FF0000");
198 }
199}