summaryrefslogtreecommitdiff
path: root/src/color.rs
diff options
context:
space:
mode:
authorMax Verevkin <maxxverrr@gmail.com>2022-04-01 21:50:19 +0300
committerMax Verevkin <maxxverrr@gmail.com>2022-04-01 21:50:19 +0300
commit7bcaa341b8685ba411d206c1a89dc3ca77aa71bb (patch)
tree917dec11c47ce71fe9486e56f94015bd12c496b7 /src/color.rs
downloadi3bar-mango-7bcaa341b8685ba411d206c1a89dc3ca77aa71bb.tar.gz
initial commit
Diffstat (limited to 'src/color.rs')
-rw-r--r--src/color.rs85
1 files changed, 85 insertions, 0 deletions
diff --git a/src/color.rs b/src/color.rs
new file mode 100644
index 0000000..7305c24
--- /dev/null
+++ b/src/color.rs
@@ -0,0 +1,85 @@
+use pangocairo::cairo::Context;
+use serde::de;
+use std::fmt;
+use std::str::FromStr;
+
+#[derive(Debug, Clone, Copy, PartialEq)]
+pub struct Color {
+ red: f64,
+ green: f64,
+ blue: f64,
+ alpha: f64,
+}
+
+impl Color {
+ pub fn apply(self, cr: &Context) {
+ if self.alpha.is_nan() {
+ cr.set_source_rgb(self.red, self.green, self.blue);
+ } else {
+ cr.set_source_rgba(self.red, self.green, self.blue, self.alpha);
+ }
+ }
+
+ pub fn from_rgba(r: u8, g: u8, b: u8, a: u8) -> Self {
+ Self {
+ red: r as f64 / 255.0,
+ green: g as f64 / 255.0,
+ blue: b as f64 / 255.0,
+ alpha: if a == 255 { f64::NAN } else { a as f64 / 255.0 },
+ }
+ }
+
+ pub fn from_rgba_hex(hex: u32) -> Self {
+ let r = (hex >> 24 & 0xFF) as u8;
+ let g = (hex >> 16 & 0xFF) as u8;
+ let b = (hex >> 8 & 0xFF) as u8;
+ let a = (hex & 0xFF) as u8;
+ Self::from_rgba(r, g, b, a)
+ }
+}
+
+impl FromStr for Color {
+ type Err = ();
+
+ fn from_str(color: &str) -> Result<Self, Self::Err> {
+ let rgb = color.get(1..7).ok_or(())?;
+ let rgb = u32::from_str_radix(rgb, 16).map_err(|_| ())?;
+ let r = (rgb >> 16 & 0xFF) as u8;
+ let g = (rgb >> 8 & 0xFF) as u8;
+ let b = (rgb & 0xFF) as u8;
+
+ let a = match color.get(7..9) {
+ Some(a) => u8::from_str_radix(a, 16).map_err(|_| ())?,
+ None => 255,
+ };
+
+ Ok(Self::from_rgba(r, g, b, a))
+ }
+}
+
+impl<'de> de::Deserialize<'de> for Color {
+ fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+ where
+ D: de::Deserializer<'de>,
+ {
+ struct ColorVisitor;
+
+ impl<'de> de::Visitor<'de> for ColorVisitor {
+ type Value = Color;
+
+ fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("RBG or RGBA color (in hex)")
+ }
+
+ fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
+ where
+ E: de::Error,
+ {
+ s.parse()
+ .map_err(|_| E::custom(format!("'{s}' is not a valid RGB/RGBA color")))
+ }
+ }
+
+ deserializer.deserialize_str(ColorVisitor)
+ }
+}