#![cfg_attr(docsrs, feature(doc_cfg))]
#![allow(clippy::tabs_in_doc_comments)]
#[cfg(feature = "macros")]
#[cfg_attr(docsrs, doc(cfg(feature = "macros")))]
pub use egui_from_hex_macros::hex;
#[cfg(feature = "macros")]
#[cfg_attr(docsrs, doc(cfg(feature = "macros")))]
pub use egui_from_hex_macros::hex_premultiplied;
use egui::Color32;
use std::fmt;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum HexParseError {
InvalidLength,
InvalidCharacter
}
impl fmt::Display for HexParseError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::InvalidCharacter => write!(f, "[ERROR] Invalid character in HEX string"),
Self::InvalidLength => write!(f, "[ERROR] Invalid HEX string length")
}
}
}
impl std::error::Error for HexParseError {}
pub trait HexColor: Sized {
fn from_u32(color: u32) -> Self;
fn from_u32_premultiplied(color: u32) -> Self;
fn from_hex(hex: &str) -> Result<Self, HexParseError>;
fn from_hex_premultiplied(hex: &str) -> Result<Self, HexParseError>;
}
impl HexColor for Color32 {
#[inline]
fn from_hex(hex: &str) -> Result<Self, HexParseError> {
let (r, g, b, a) = parse_hex_to_rgba(hex)?;
Ok(Self::from_rgba_unmultiplied(r, g, b, a))
}
#[inline]
fn from_hex_premultiplied(hex: &str) -> Result<Self, HexParseError> {
let (r, g, b, a) = parse_hex_to_rgba(hex)?;
Ok(Self::from_rgba_premultiplied(r, g, b, a))
}
#[inline]
fn from_u32(color: u32) -> Self {
let (r, g, b, a) = (
(color >> 24) as u8,
(color >> 16) as u8,
(color >> 8) as u8,
(color) as u8,
);
Self::from_rgba_unmultiplied(r, g, b, a)
}
#[inline]
fn from_u32_premultiplied(color: u32) -> Self {
let (r, g, b, a) = (
(color >> 24) as u8,
(color >> 16) as u8,
(color >> 8) as u8,
color as u8,
);
Self::from_rgba_premultiplied(r, g, b, a)
}
}
fn parse_hex_to_rgba(hex: &str) -> Result<(u8, u8, u8, u8), HexParseError> {
let bytes = hex.as_bytes();
let start = match bytes {
[b'0', b'x', ..] => 2,
[b'#', ..] | [b'x', ..] => 1,
_ => 0,
};
let s = &bytes[start..];
fn hv(b: u8) -> Result<u8, HexParseError> {
match b {
b'0'..=b'9' => Ok(b - b'0'),
b'a'..=b'f' => Ok(b - b'a' + 10),
b'A'..=b'F' => Ok(b - b'A' + 10),
_ => Err(HexParseError::InvalidCharacter),
}
}
match s.len() {
3 => Ok((
(hv(s[0])? << 4) | hv(s[0])?,
(hv(s[1])? << 4) | hv(s[1])?,
(hv(s[2])? << 4) | hv(s[2])?,
255,
)),
4 => Ok((
(hv(s[0])? << 4) | hv(s[0])?,
(hv(s[1])? << 4) | hv(s[1])?,
(hv(s[2])? << 4) | hv(s[2])?,
(hv(s[3])? << 4) | hv(s[3])?,
)),
6 => Ok((
(hv(s[0])? << 4) | hv(s[1])?,
(hv(s[2])? << 4) | hv(s[3])?,
(hv(s[4])? << 4) | hv(s[5])?,
255,
)),
8 => Ok((
(hv(s[0])? << 4) | hv(s[1])?,
(hv(s[2])? << 4) | hv(s[3])?,
(hv(s[4])? << 4) | hv(s[5])?,
(hv(s[6])? << 4) | hv(s[7])?,
)),
_ => Err(HexParseError::InvalidLength),
}
}
#[doc(hidden)]
pub fn __internal_parse_hex(hex: &str) -> Result<(u8, u8, u8, u8), HexParseError> {
parse_hex_to_rgba(hex)
}