init color crate
This commit is contained in:
parent
acf85db44e
commit
8c9f3a7322
4 changed files with 225 additions and 2 deletions
76
Cargo.lock
generated
76
Cargo.lock
generated
|
@ -1580,6 +1580,28 @@ dependencies = [
|
||||||
"rustc-hash",
|
"rustc-hash",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "color"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
|
"fs",
|
||||||
|
"indexmap 1.9.3",
|
||||||
|
"itertools 0.11.0",
|
||||||
|
"palette",
|
||||||
|
"parking_lot 0.11.2",
|
||||||
|
"refineable",
|
||||||
|
"schemars",
|
||||||
|
"serde",
|
||||||
|
"serde_derive",
|
||||||
|
"serde_json",
|
||||||
|
"settings",
|
||||||
|
"story",
|
||||||
|
"toml 0.5.11",
|
||||||
|
"util",
|
||||||
|
"uuid 1.4.1",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "color_quant"
|
name = "color_quant"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
|
@ -4976,6 +4998,7 @@ dependencies = [
|
||||||
"approx",
|
"approx",
|
||||||
"fast-srgb8",
|
"fast-srgb8",
|
||||||
"palette_derive",
|
"palette_derive",
|
||||||
|
"phf",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -5164,6 +5187,48 @@ dependencies = [
|
||||||
"indexmap 2.0.0",
|
"indexmap 2.0.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "phf"
|
||||||
|
version = "0.11.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc"
|
||||||
|
dependencies = [
|
||||||
|
"phf_macros",
|
||||||
|
"phf_shared",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "phf_generator"
|
||||||
|
version = "0.11.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0"
|
||||||
|
dependencies = [
|
||||||
|
"phf_shared",
|
||||||
|
"rand 0.8.5",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "phf_macros"
|
||||||
|
version = "0.11.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3444646e286606587e49f3bcf1679b8cef1dc2c5ecc29ddacaffc305180d464b"
|
||||||
|
dependencies = [
|
||||||
|
"phf_generator",
|
||||||
|
"phf_shared",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.37",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "phf_shared"
|
||||||
|
version = "0.11.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b"
|
||||||
|
dependencies = [
|
||||||
|
"siphasher 0.3.11",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "picker"
|
name = "picker"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
@ -7073,6 +7138,12 @@ version = "0.2.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0b8de496cf83d4ed58b6be86c3a275b8602f6ffe98d3024a869e124147a9a3ac"
|
checksum = "0b8de496cf83d4ed58b6be86c3a275b8602f6ffe98d3024a869e124147a9a3ac"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "siphasher"
|
||||||
|
version = "0.3.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "slab"
|
name = "slab"
|
||||||
version = "0.4.9"
|
version = "0.4.9"
|
||||||
|
@ -7643,7 +7714,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9c536faaff1a10837cfe373142583f6e27d81e96beba339147e77b67c9f260ff"
|
checksum = "9c536faaff1a10837cfe373142583f6e27d81e96beba339147e77b67c9f260ff"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"float-cmp",
|
"float-cmp",
|
||||||
"siphasher",
|
"siphasher 0.2.3",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -8857,7 +8928,7 @@ dependencies = [
|
||||||
"roxmltree",
|
"roxmltree",
|
||||||
"rustybuzz",
|
"rustybuzz",
|
||||||
"simplecss",
|
"simplecss",
|
||||||
"siphasher",
|
"siphasher 0.2.3",
|
||||||
"svgtypes",
|
"svgtypes",
|
||||||
"ttf-parser 0.12.3",
|
"ttf-parser 0.12.3",
|
||||||
"unicode-bidi",
|
"unicode-bidi",
|
||||||
|
@ -9649,6 +9720,7 @@ dependencies = [
|
||||||
"client",
|
"client",
|
||||||
"collab_ui",
|
"collab_ui",
|
||||||
"collections",
|
"collections",
|
||||||
|
"color",
|
||||||
"command_palette",
|
"command_palette",
|
||||||
"copilot",
|
"copilot",
|
||||||
"copilot_ui",
|
"copilot_ui",
|
||||||
|
|
32
crates/color/Cargo.toml
Normal file
32
crates/color/Cargo.toml
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
[package]
|
||||||
|
name = "color"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
publish = false
|
||||||
|
|
||||||
|
[features]
|
||||||
|
default = []
|
||||||
|
stories = ["dep:itertools", "dep:story"]
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
path = "src/color.rs"
|
||||||
|
doctest = true
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
# TODO: Clean up dependencies
|
||||||
|
anyhow.workspace = true
|
||||||
|
fs = { path = "../fs" }
|
||||||
|
indexmap = "1.6.2"
|
||||||
|
parking_lot.workspace = true
|
||||||
|
refineable.workspace = true
|
||||||
|
schemars.workspace = true
|
||||||
|
serde.workspace = true
|
||||||
|
serde_derive.workspace = true
|
||||||
|
serde_json.workspace = true
|
||||||
|
settings = { path = "../settings" }
|
||||||
|
story = { path = "../story", optional = true }
|
||||||
|
toml.workspace = true
|
||||||
|
uuid.workspace = true
|
||||||
|
util = { path = "../util" }
|
||||||
|
itertools = { version = "0.11.0", optional = true }
|
||||||
|
palette = "0.7.3"
|
118
crates/color/src/color.rs
Normal file
118
crates/color/src/color.rs
Normal file
|
@ -0,0 +1,118 @@
|
||||||
|
//! # Color
|
||||||
|
//!
|
||||||
|
//! The `color` crate provides a set utilities for working with colors. It is a wrapper around the [`palette`](https://docs.rs/palette) crate with some additional functionality.
|
||||||
|
//!
|
||||||
|
//! It is used to create a manipulate colors when building themes.
|
||||||
|
//!
|
||||||
|
//! **Note:** This crate does not depend on `gpui`, so it does not provide any
|
||||||
|
//! interfaces for converting to `gpui` style colors.
|
||||||
|
|
||||||
|
use palette::{FromColor, Hsl, Hsla, Mix, Srgba, WithAlpha};
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||||
|
pub enum BlendMode {
|
||||||
|
Multiply,
|
||||||
|
Screen,
|
||||||
|
Overlay,
|
||||||
|
Darken,
|
||||||
|
Lighten,
|
||||||
|
Dodge,
|
||||||
|
Burn,
|
||||||
|
HardLight,
|
||||||
|
SoftLight,
|
||||||
|
Difference,
|
||||||
|
Exclusion,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a new [`palette::Hsl`] color.
|
||||||
|
pub fn hsl(h: f32, s: f32, l: f32) -> Hsl {
|
||||||
|
Hsl::new_srgb(h, s, l)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Converts a hexadecimal color string to a `palette::Hsla` color.
|
||||||
|
///
|
||||||
|
/// This function supports the following hex formats:
|
||||||
|
/// `#RGB`, `#RGBA`, `#RRGGBB`, `#RRGGBBAA`.
|
||||||
|
pub fn hex_to_hsla(s: &str) -> Result<Hsla, String> {
|
||||||
|
let hex = s.trim_start_matches('#');
|
||||||
|
|
||||||
|
// Expand shorthand formats #RGB and #RGBA to #RRGGBB and #RRGGBBAA
|
||||||
|
let hex = match hex.len() {
|
||||||
|
3 => hex
|
||||||
|
.chars()
|
||||||
|
.map(|c| c.to_string().repeat(2))
|
||||||
|
.collect::<String>(),
|
||||||
|
4 => {
|
||||||
|
let (rgb, alpha) = hex.split_at(3);
|
||||||
|
let rgb = rgb
|
||||||
|
.chars()
|
||||||
|
.map(|c| c.to_string().repeat(2))
|
||||||
|
.collect::<String>();
|
||||||
|
let alpha = alpha.chars().next().unwrap().to_string().repeat(2);
|
||||||
|
format!("{}{}", rgb, alpha)
|
||||||
|
}
|
||||||
|
6 => format!("{}ff", hex), // Add alpha if missing
|
||||||
|
8 => hex.to_string(), // Already in full format
|
||||||
|
_ => return Err("Invalid hexadecimal string length".to_string()),
|
||||||
|
};
|
||||||
|
|
||||||
|
let hex_val =
|
||||||
|
u32::from_str_radix(&hex, 16).map_err(|_| format!("Invalid hexadecimal string: {}", s))?;
|
||||||
|
|
||||||
|
let r = ((hex_val >> 24) & 0xFF) as f32 / 255.0;
|
||||||
|
let g = ((hex_val >> 16) & 0xFF) as f32 / 255.0;
|
||||||
|
let b = ((hex_val >> 8) & 0xFF) as f32 / 255.0;
|
||||||
|
let a = (hex_val & 0xFF) as f32 / 255.0;
|
||||||
|
|
||||||
|
let srgba = Srgba::new(r, g, b, a);
|
||||||
|
let hsl = Hsl::from_color(srgba);
|
||||||
|
let hsla = Hsla::from(hsl).with_alpha(a);
|
||||||
|
|
||||||
|
Ok(hsla)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Mixes two [`palette::Hsl`] colors at the given `mix_ratio`.
|
||||||
|
pub fn hsl_mix(hsla_1: Hsl, hsla_2: Hsl, mix_ratio: f32) -> Hsl {
|
||||||
|
hsla_1.mix(hsla_2, mix_ratio).into()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Represents a color
|
||||||
|
/// An interstitial state used to provide a consistent API for colors
|
||||||
|
/// with additional functionality like color mixing, blending, etc.
|
||||||
|
///
|
||||||
|
/// Does not return [gpui] colors as the `color` crate does not
|
||||||
|
/// depend on [gpui].
|
||||||
|
#[derive(Debug, Copy, Clone)]
|
||||||
|
pub struct Color {
|
||||||
|
value: Hsla,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Color {
|
||||||
|
/// Creates a new [`Color`]
|
||||||
|
pub fn new(hue: f32, saturation: f32, lightness: f32) -> Self {
|
||||||
|
let hsl = hsl(hue, saturation, lightness);
|
||||||
|
|
||||||
|
Self { value: hsl.into() }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a new [`Color`] with an alpha value.
|
||||||
|
pub fn from_hsla(hue: f32, saturation: f32, lightness: f32, alpha: f32) -> Self {
|
||||||
|
Self {
|
||||||
|
value: Hsla::new(hue, saturation, lightness, alpha),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the [`palette::Hsla`] value of this color.
|
||||||
|
pub fn value(&self) -> Hsla {
|
||||||
|
self.value
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Mixes this color with another [`palette::Hsl`] color at the given `mix_ratio`.
|
||||||
|
pub fn mix(&self, other: Hsl, mix_ratio: f32) -> Self {
|
||||||
|
let mixed = self.value.mix(other.into(), mix_ratio);
|
||||||
|
|
||||||
|
Self {
|
||||||
|
value: mixed.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -29,6 +29,7 @@ command_palette = { path = "../command_palette" }
|
||||||
# component_test = { path = "../component_test" }
|
# component_test = { path = "../component_test" }
|
||||||
client = { path = "../client" }
|
client = { path = "../client" }
|
||||||
# clock = { path = "../clock" }
|
# clock = { path = "../clock" }
|
||||||
|
color = { path = "../color" }
|
||||||
copilot = { path = "../copilot" }
|
copilot = { path = "../copilot" }
|
||||||
copilot_ui = { path = "../copilot_ui" }
|
copilot_ui = { path = "../copilot_ui" }
|
||||||
diagnostics = { path = "../diagnostics" }
|
diagnostics = { path = "../diagnostics" }
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue