diff --git a/Cargo.lock b/Cargo.lock index c014a0763..b33580b56 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -608,6 +608,12 @@ dependencies = [ "unicode-width", ] +[[package]] +name = "color-hex" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecdffb913a326b6c642290a0d0ec8e8d6597291acdc07cc4c9cb4b3635d44cf9" + [[package]] name = "color_quant" version = "1.1.0" @@ -1347,6 +1353,7 @@ dependencies = [ "atomic_refcell", "bytemuck", "cint", + "color-hex", "criterion", "emath", "nohash-hasher", diff --git a/egui/src/lib.rs b/egui/src/lib.rs index d521eb5db..0f5d45a1f 100644 --- a/egui/src/lib.rs +++ b/egui/src/lib.rs @@ -323,7 +323,7 @@ pub use epaint::emath; pub use emath::{lerp, pos2, remap, remap_clamp, vec2, Align, Align2, NumExt, Pos2, Rect, Vec2}; pub use epaint::{ - color, mutex, + color, hex_color, mutex, text::{FontData, FontDefinitions, FontFamily, FontId, FontTweak}, textures::TexturesDelta, ClippedPrimitive, Color32, ColorImage, FontImage, ImageData, Mesh, PaintCallback, diff --git a/epaint/CHANGELOG.md b/epaint/CHANGELOG.md index 9612e77b6..45949d28f 100644 --- a/epaint/CHANGELOG.md +++ b/epaint/CHANGELOG.md @@ -4,7 +4,7 @@ All notable changes to the epaint crate will be documented in this file. ## Unreleased * Optimize tessellation of filled circles by 10x or more ([#1616](https://github.com/emilk/egui/pull/1616)). - +* Added `epaint::hex_rgb*!()` macros to create Color32's from hex strings ([#1596](https://github.com/emilk/egui/pull/1596)). ## 0.18.1 - 2022-05-01 * Change `Shape::Callback` from `&dyn Any` to `&mut dyn Any` to support more backends. diff --git a/epaint/Cargo.toml b/epaint/Cargo.toml index 1c1ff6be3..2a39aad02 100644 --- a/epaint/Cargo.toml +++ b/epaint/Cargo.toml @@ -47,13 +47,14 @@ mint = ["emath/mint"] # implement serde on most types. serde = ["dep:serde", "ahash/serde", "emath/serde"] - [dependencies] emath = { version = "0.18.0", path = "../emath" } ab_glyph = "0.2.11" nohash-hasher = "0.2" +color-hex = "0.2.0" + # Optional: ahash = { version = "0.7", default-features = false, features = ["std"] } bytemuck = { version = "1.7.2", optional = true, features = ["derive"] } diff --git a/epaint/src/color.rs b/epaint/src/color.rs index c88daacf2..c603872db 100644 --- a/epaint/src/color.rs +++ b/epaint/src/color.rs @@ -125,27 +125,27 @@ impl Color32 { } #[inline(always)] - pub fn is_opaque(&self) -> bool { + pub const fn is_opaque(&self) -> bool { self.a() == 255 } #[inline(always)] - pub fn r(&self) -> u8 { + pub const fn r(&self) -> u8 { self.0[0] } #[inline(always)] - pub fn g(&self) -> u8 { + pub const fn g(&self) -> u8 { self.0[1] } #[inline(always)] - pub fn b(&self) -> u8 { + pub const fn b(&self) -> u8 { self.0[2] } #[inline(always)] - pub fn a(&self) -> u8 { + pub const fn a(&self) -> u8 { self.0[3] } @@ -156,20 +156,20 @@ impl Color32 { /// Returns an additive version of self #[inline(always)] - pub fn additive(self) -> Self { + pub const fn additive(self) -> Self { let [r, g, b, _] = self.to_array(); Self([r, g, b, 0]) } /// Premultiplied RGBA #[inline(always)] - pub fn to_array(&self) -> [u8; 4] { + pub const fn to_array(&self) -> [u8; 4] { [self.r(), self.g(), self.b(), self.a()] } /// Premultiplied RGBA #[inline(always)] - pub fn to_tuple(&self) -> (u8, u8, u8, u8) { + pub const fn to_tuple(&self) -> (u8, u8, u8, u8) { (self.r(), self.g(), self.b(), self.a()) } @@ -186,6 +186,42 @@ impl Color32 { } } +/// Construct a [`Color32`] from a hex RGB or RGBA string. +/// +/// ```ignore +/// assert_eq!(hex_color!("#202122"), Color32::from_rgb(0x20, 0x21, 0x22)); +/// assert_eq!(hex_color!("#abcdef12"), Color32::from_rgba_unmultiplied(0xab, 0xcd, 0xef, 0x12)); +/// ``` +#[macro_export] +macro_rules! hex_color { + ($s:literal) => {{ + let array = $crate::color_hex::color_from_hex!($s); + if array.len() == 3 { + $crate::Color32::from_rgb(array[0], array[1], array[2]) + } else { + #[allow(unconditional_panic)] + $crate::Color32::from_rgba_unmultiplied(array[0], array[1], array[2], array[3]) + } + }}; +} + +#[test] +fn test_from_rgb_hex() { + assert_eq!(Color32::from_rgb(0x20, 0x21, 0x22), hex_color!("#202122")); + assert_eq!( + Color32::from_rgb_additive(0x20, 0x21, 0x22), + hex_color!("#202122").additive() + ); +} + +#[test] +fn test_from_rgba_hex() { + assert_eq!( + Color32::from_rgba_unmultiplied(0x20, 0x21, 0x22, 0x50), + hex_color!("20212250") + ); +} + // ---------------------------------------------------------------------------- /// 0-1 linear space `RGBA` color with premultiplied alpha. diff --git a/epaint/src/lib.rs b/epaint/src/lib.rs index 3c6422977..5cd17c1fa 100644 --- a/epaint/src/lib.rs +++ b/epaint/src/lib.rs @@ -49,6 +49,8 @@ pub use emath::{pos2, vec2, Pos2, Rect, Vec2}; pub use ahash; pub use emath; +pub use color_hex; + /// The UV coordinate of a white region of the texture mesh. /// The default egui texture has the top-left corner pixel fully white. /// You need need use a clamping texture sampler for this to work