Skip to content

Commit

Permalink
Merge pull request #200 from clarkmoody/color-enhancements
Browse files Browse the repository at this point in the history
Color Enhancements
  • Loading branch information
hecrj authored May 4, 2020
2 parents e0aa89c + c0fd5de commit 27aad74
Show file tree
Hide file tree
Showing 8 changed files with 621 additions and 5 deletions.
4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ debug = ["iced_winit/debug"]
tokio = ["iced_futures/tokio"]
# Enables `async-std` as the `executor::Default` on native platforms
async-std = ["iced_futures/async-std"]
# Enables advanced color conversion via `palette`
palette = ["iced_core/palette"]

[badges]
maintenance = { status = "actively-developed" }
Expand All @@ -39,6 +41,7 @@ members = [
"winit",
"examples/bezier_tool",
"examples/clock",
"examples/color_palette",
"examples/counter",
"examples/custom_widget",
"examples/download_progress",
Expand All @@ -57,6 +60,7 @@ members = [
]

[dependencies]
iced_core = { version = "0.2", path = "core" }
iced_futures = { version = "0.1", path = "futures" }

[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
Expand Down
4 changes: 4 additions & 0 deletions core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,7 @@ license = "MIT"
repository = "https://github.com/hecrj/iced"

[dependencies]

[dependencies.palette]
version = "0.5.0"
optional = true
148 changes: 143 additions & 5 deletions core/src/color.rs
Original file line number Diff line number Diff line change
@@ -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,
}

Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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
}
);
}
}
1 change: 1 addition & 0 deletions examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ A bunch of simpler examples exist:

- [`bezier_tool`](bezier_tool), a Paint-like tool for drawing Bézier curves using [`lyon`].
- [`clock`](clock), an application that uses the `Canvas` widget to draw a clock and its hands to display the current time.
- [`color_palette`](color_palette), a color palette generator based on a user-defined root color.
- [`counter`](counter), the classic counter example explained in the [`README`](../README.md).
- [`custom_widget`](custom_widget), a demonstration of how to build a custom widget that draws a circle.
- [`download_progress`](download_progress), a basic application that asynchronously downloads a dummy file of 100 MB and tracks the download progress.
Expand Down
10 changes: 10 additions & 0 deletions examples/color_palette/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[package]
name = "color_palette"
version = "0.1.0"
authors = ["Clark Moody <clark@clarkmoody.com>"]
edition = "2018"
publish = false

[dependencies]
iced = { path = "../..", features = ["canvas", "palette"] }
palette = "0.5.0"
15 changes: 15 additions & 0 deletions examples/color_palette/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
## Color palette

A color palette generator, based on a user-defined root color.

<div align="center">
<a href="https://gfycat.com/dirtylonebighornsheep">
<img src="https://github.com/hecrj/iced/raw/1a8d253611d3796b0a32b2f096bb54565a5292e0/examples/color_palette/screenshot.png">
</a>
</div>

You can run it with `cargo run`:

```
cargo run --package color_palette
```
Binary file added examples/color_palette/screenshot.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit 27aad74

Please sign in to comment.