|
@@ -1,16 +1,17 @@
|
|
-use xcb::render::Color;
|
|
|
|
|
|
+use serde::{de, Deserialize, Deserializer};
|
|
|
|
+use xcb;
|
|
use xcb::ffi::render::xcb_render_color_t;
|
|
use xcb::ffi::render::xcb_render_color_t;
|
|
|
|
|
|
macro_rules! color_const {
|
|
macro_rules! color_const {
|
|
($name:ident, $r:expr, $g:expr, $b:expr, $a:expr) => {
|
|
($name:ident, $r:expr, $g:expr, $b:expr, $a:expr) => {
|
|
- pub const $name: Color = Color {
|
|
|
|
|
|
+ pub const $name: Color = Color(xcb::render::Color {
|
|
base: xcb_render_color_t {
|
|
base: xcb_render_color_t {
|
|
red: $r,
|
|
red: $r,
|
|
green: $g,
|
|
green: $g,
|
|
blue: $b,
|
|
blue: $b,
|
|
alpha: $a
|
|
alpha: $a
|
|
}
|
|
}
|
|
- };
|
|
|
|
|
|
+ });
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
@@ -20,34 +21,60 @@ color_const!(GREY, 0x6666, 0x6666, 0x6666, 0xFFFF);
|
|
color_const!(LIGHT_GREEN, 0x6666, 0xCCCC, 0x6666, 0xFFFF);
|
|
color_const!(LIGHT_GREEN, 0x6666, 0xCCCC, 0x6666, 0xFFFF);
|
|
color_const!(RED, 0xCCCC, 0x0000, 0x3333, 0xFFFF);
|
|
color_const!(RED, 0xCCCC, 0x0000, 0x3333, 0xFFFF);
|
|
|
|
|
|
-fn double(num: u16) -> u16 {
|
|
|
|
- num << 8 | num
|
|
|
|
-}
|
|
|
|
|
|
+#[derive(Copy, Clone)]
|
|
|
|
+pub struct Color(xcb::render::Color);
|
|
|
|
|
|
-pub fn from_str(input: &str) -> Option<Color> {
|
|
|
|
- if input.len() != 7 {
|
|
|
|
- return None
|
|
|
|
|
|
+impl Color {
|
|
|
|
+ pub fn as_xcb(&self) -> xcb::render::Color {
|
|
|
|
+ self.0
|
|
}
|
|
}
|
|
- let (head, body) = input.split_at(1);
|
|
|
|
- if head != "#" {
|
|
|
|
- return None
|
|
|
|
|
|
+
|
|
|
|
+ pub fn as_u32(&self) -> u32 {
|
|
|
|
+ let color = self.0;
|
|
|
|
+ (color.alpha() as u32 % 256) << 24 |
|
|
|
|
+ (color.red() as u32 % 256) << 16 |
|
|
|
|
+ (color.green() as u32 % 256) << 16 |
|
|
|
|
+ (color.blue() as u32 % 256)
|
|
}
|
|
}
|
|
- let valid = "0123456789ABCDEF";
|
|
|
|
- if !body.chars().all(|c| valid.contains(c)) {
|
|
|
|
- return None
|
|
|
|
|
|
+
|
|
|
|
+ pub fn from_str(input: &str) -> Option<Color> {
|
|
|
|
+ if input.len() != 7 {
|
|
|
|
+ return None
|
|
|
|
+ }
|
|
|
|
+ let (head, body) = input.split_at(1);
|
|
|
|
+ if head != "#" {
|
|
|
|
+ return None
|
|
|
|
+ }
|
|
|
|
+ let valid = "0123456789ABCDEF";
|
|
|
|
+ if !body.chars().all(|c| valid.contains(c)) {
|
|
|
|
+ return None
|
|
|
|
+ }
|
|
|
|
+ let mut num = u32::from_str_radix(body, 16).unwrap();
|
|
|
|
+ let blue = (num % 256) as u16;
|
|
|
|
+ num >>= 8;
|
|
|
|
+ let green = (num % 256) as u16;
|
|
|
|
+ num >>= 8;
|
|
|
|
+ let red = (num % 256) as u16;
|
|
|
|
+
|
|
|
|
+ let xcb_color = xcb::render::Color::new(double(red), double(green), double(blue), 0xFFFF);
|
|
|
|
+ Some(Color(xcb_color))
|
|
}
|
|
}
|
|
- let mut num = u32::from_str_radix(body, 16).unwrap();
|
|
|
|
- let blue = (num % 256) as u16;
|
|
|
|
- num >>= 8;
|
|
|
|
- let green = (num % 256) as u16;
|
|
|
|
- num >>= 8;
|
|
|
|
- let red = (num % 256) as u16;
|
|
|
|
- Some(Color::new(double(red), double(green), double(blue), 0xFFFF))
|
|
|
|
|
|
+
|
|
}
|
|
}
|
|
|
|
|
|
-pub fn as_u32(input: Color) -> u32 {
|
|
|
|
- (input.alpha() as u32 % 256) << 24 |
|
|
|
|
- (input.red() as u32 % 256) << 16 |
|
|
|
|
- (input.green() as u32 % 256) << 16 |
|
|
|
|
- (input.blue() as u32 % 256)
|
|
|
|
|
|
+impl<'de> Deserialize<'de> for Color {
|
|
|
|
+ fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
|
|
|
+ where D: Deserializer<'de>
|
|
|
|
+ {
|
|
|
|
+ let s = <String>::deserialize(deserializer)?;
|
|
|
|
+ match Color::from_str(&s) {
|
|
|
|
+ Some(color) => Ok(color),
|
|
|
|
+ None => Err(de::Error::custom("Could not map color"))
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+fn double(num: u16) -> u16 {
|
|
|
|
+ num << 8 | num
|
|
}
|
|
}
|