diff options
author | 2020-05-04 23:35:09 +0200 | |
---|---|---|
committer | 2020-05-04 23:35:09 +0200 | |
commit | 67b2ccb4d5ae19d7c325f973b51fb02db03c853c (patch) | |
tree | de0c3fc4ad546403cf68b1dfb0a50db94e9f3197 /core | |
parent | 2f41ccee1c7b52f872d68d2e5ebd68ea49a1559b (diff) | |
parent | 27aad74a32fd8ac2b12f9d32df8a3b61a3175457 (diff) | |
download | iced-67b2ccb4d5ae19d7c325f973b51fb02db03c853c.tar.gz iced-67b2ccb4d5ae19d7c325f973b51fb02db03c853c.tar.bz2 iced-67b2ccb4d5ae19d7c325f973b51fb02db03c853c.zip |
Merge branch 'master' into feature/canvas-interaction
Diffstat (limited to 'core')
-rw-r--r-- | core/Cargo.toml | 4 | ||||
-rw-r--r-- | core/src/color.rs | 148 |
2 files changed, 147 insertions, 5 deletions
diff --git a/core/Cargo.toml b/core/Cargo.toml index 837f6aae..b52bf315 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -8,3 +8,7 @@ license = "MIT" repository = "https://github.com/hecrj/iced" [dependencies] + +[dependencies.palette] +version = "0.5.0" +optional = true diff --git a/core/src/color.rs b/core/src/color.rs index db509b88..a4c3d87c 100644 --- a/core/src/color.rs +++ b/core/src/color.rs @@ -1,10 +1,16 @@ +#[cfg(feature = "palette")] +use palette::rgb::{Srgb, Srgba}; + /// A color in the sRGB color space. -#[derive(Debug, Clone, Copy, PartialEq)] -#[allow(missing_docs)] +#[derive(Debug, Clone, Copy, PartialEq, Default)] pub struct Color { + /// Red component, 0.0 - 1.0 pub r: f32, + /// Green component, 0.0 - 1.0 pub g: f32, + /// Blue component, 0.0 - 1.0 pub b: f32, + /// Transparency, 0.0 - 1.0 pub a: f32, } @@ -33,11 +39,45 @@ impl Color { a: 0.0, }; + /// Creates a new [`Color`]. + /// + /// In debug mode, it will panic if the values are not in the correct + /// range: 0.0 - 1.0 + /// + /// [`Color`]: struct.Color.html + pub fn new(r: f32, g: f32, b: f32, a: f32) -> Color { + debug_assert!( + (0.0..=1.0).contains(&r), + "Red component must be on [0, 1]" + ); + debug_assert!( + (0.0..=1.0).contains(&g), + "Green component must be on [0, 1]" + ); + debug_assert!( + (0.0..=1.0).contains(&b), + "Blue component must be on [0, 1]" + ); + debug_assert!( + (0.0..=1.0).contains(&a), + "Alpha component must be on [0, 1]" + ); + + Color { r, g, b, a } + } + /// Creates a [`Color`] from its RGB components. /// /// [`Color`]: struct.Color.html pub const fn from_rgb(r: f32, g: f32, b: f32) -> Color { - Color { r, g, b, a: 1.0 } + Color::from_rgba(r, g, b, 1.0f32) + } + + /// Creates a [`Color`] from its RGBA components. + /// + /// [`Color`]: struct.Color.html + pub const fn from_rgba(r: f32, g: f32, b: f32, a: f32) -> Color { + Color { r, g, b, a } } /// Creates a [`Color`] from its RGB8 components. @@ -80,16 +120,114 @@ impl Color { self.a, ] } + + /// Inverts the [`Color`] in-place. + /// + /// [`Color`]: struct.Color.html + pub fn invert(&mut self) { + self.r = 1.0f32 - self.r; + self.b = 1.0f32 - self.g; + self.g = 1.0f32 - self.b; + } + + /// Returns the inverted [`Color`]. + /// + /// [`Color`]: struct.Color.html + pub fn inverse(self) -> Color { + Color::new(1.0f32 - self.r, 1.0f32 - self.g, 1.0f32 - self.b, self.a) + } } impl From<[f32; 3]> for Color { fn from([r, g, b]: [f32; 3]) -> Self { - Color { r, g, b, a: 1.0 } + Color::new(r, g, b, 1.0) } } impl From<[f32; 4]> for Color { fn from([r, g, b, a]: [f32; 4]) -> Self { - Color { r, g, b, a } + Color::new(r, g, b, a) + } +} + +#[cfg(feature = "palette")] +/// Converts from palette's `Srgba` type to a [`Color`]. +/// +/// [`Color`]: struct.Color.html +impl From<Srgba> for Color { + fn from(srgba: Srgba) -> Self { + Color::new(srgba.red, srgba.green, srgba.blue, srgba.alpha) + } +} + +#[cfg(feature = "palette")] +/// Converts from [`Color`] to palette's `Srgba` type. +/// +/// [`Color`]: struct.Color.html +impl From<Color> for Srgba { + fn from(c: Color) -> Self { + Srgba::new(c.r, c.g, c.b, c.a) + } +} + +#[cfg(feature = "palette")] +/// Converts from palette's `Srgb` type to a [`Color`]. +/// +/// [`Color`]: struct.Color.html +impl From<Srgb> for Color { + fn from(srgb: Srgb) -> Self { + Color::new(srgb.red, srgb.green, srgb.blue, 1.0) + } +} + +#[cfg(feature = "palette")] +/// Converts from [`Color`] to palette's `Srgb` type. +/// +/// [`Color`]: struct.Color.html +/// [`Srgb`]: ../palette/rgb/type.Srgb.html +impl From<Color> for Srgb { + fn from(c: Color) -> Self { + Srgb::new(c.r, c.g, c.b) + } +} + +#[cfg(feature = "palette")] +#[cfg(test)] +mod tests { + use super::*; + use palette::Blend; + + #[test] + fn srgba_traits() { + let c = Color::from_rgb(0.5, 0.4, 0.3); + // Round-trip conversion to the palette:Srgba type + let s: Srgba = c.into(); + let r: Color = s.into(); + assert_eq!(c, r); + } + + #[test] + fn color_manipulation() { + let c1 = Color::from_rgb(0.5, 0.4, 0.3); + let c2 = Color::from_rgb(0.2, 0.5, 0.3); + + // Convert to linear color for manipulation + let l1 = Srgba::from(c1).into_linear(); + let l2 = Srgba::from(c2).into_linear(); + + // Take the lighter of each of the RGB components + let lighter = l1.lighten(l2); + + // Convert back to our Color + let r: Color = Srgba::from_linear(lighter).into(); + assert_eq!( + r, + Color { + r: 0.5, + g: 0.5, + b: 0.3, + a: 1.0 + } + ); } } |