Skip to content

Commit 94d4377

Browse files
committed
New Color constructors: from_html, from_rgba_u8, from_rgba_u32
1 parent 186282b commit 94d4377

File tree

1 file changed

+83
-0
lines changed

1 file changed

+83
-0
lines changed

gdnative-core/src/core_types/color.rs

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,88 @@ impl Color {
4141
Color::from_sys(unsafe { (get_api().godot_color_from_hsv)(color.sys(), h, s, v, a) })
4242
}
4343

44+
/// Parses from a HTML color code, or `None` on parse error.
45+
///
46+
/// ```
47+
/// use gdnative::prelude::Color;
48+
///
49+
/// // Each of the following creates the same color RGBA(178, 217, 10, 255).
50+
/// let c1 = Color::from_html("#9eb2d90a"); // ARGB format with "#".
51+
/// let c2 = Color::from_html("9eb2d90a"); // ARGB format.
52+
/// let c3 = Color::from_html("#b2d90a"); // RGB format with "#".
53+
/// let c4 = Color::from_html("b2d90a"); // RGB format.
54+
///
55+
/// let expected = Color::from_rgba_u8(178, 217, 10, 158);
56+
/// assert_eq!(c1, Some(expected));
57+
/// assert_eq!(c2, Some(expected));
58+
///
59+
/// let expected = Color::from_rgba_u8(178, 217, 10, 255);
60+
/// assert_eq!(c3, Some(expected));
61+
/// assert_eq!(c4, Some(expected));
62+
/// ```
63+
///
64+
/// See also the corresponding [GDScript method](https://docs.godotengine.org/en/stable/classes/class_color.html#class-color-method-color).
65+
#[inline]
66+
pub fn from_html(mut argb_or_rgb: &str) -> Option<Self> {
67+
if let Some(stripped) = argb_or_rgb.strip_prefix('#') {
68+
argb_or_rgb = stripped;
69+
}
70+
71+
let (rgb_str, a) = match argb_or_rgb.len() {
72+
6 => (argb_or_rgb, 0xFF),
73+
8 => {
74+
let (a_str, rgb_str) = argb_or_rgb.split_at(2);
75+
if let Ok(a) = u8::from_str_radix(a_str, 16) {
76+
(rgb_str, a)
77+
} else {
78+
return None;
79+
}
80+
}
81+
_ => return None,
82+
};
83+
84+
if let Ok(rgb) = u32::from_str_radix(rgb_str, 16) {
85+
let color = Self::from_rgba_u32(rgb << 8 | a as u32);
86+
Some(color)
87+
} else {
88+
None
89+
}
90+
}
91+
92+
/// Construct a color from a single `u32` value, in `RGBA` format.
93+
///
94+
/// Example:
95+
/// ```
96+
/// use gdnative::prelude::Color;
97+
///
98+
/// // RGBA (178, 217, 10, 158)
99+
/// let one = Color::from_rgba_u32(0xb2d90a9e);
100+
/// let piecewise = Color::from_rgba_u8(0xB2, 0xD9, 0x0A, 0x9E);
101+
/// assert_eq!(one, piecewise);
102+
/// ```
103+
#[inline]
104+
pub fn from_rgba_u32(rgba: u32) -> Self {
105+
Self::from_rgba_u8(
106+
(rgba >> 24) as u8,
107+
((rgba >> 16) & 0xFF) as u8,
108+
((rgba >> 8) & 0xFF) as u8,
109+
(rgba & 0xFF) as u8,
110+
)
111+
}
112+
113+
/// Constructs a color from four integer channels, each in range 0-255.
114+
///
115+
/// This corresponds to the [GDScript method `Color8`](https://docs.godotengine.org/en/stable/classes/class_%40gdscript.html#class-gdscript-method-color8)
116+
#[inline]
117+
pub fn from_rgba_u8(r: u8, g: u8, b: u8, a: u8) -> Self {
118+
Self::from_rgba(
119+
r as f32 / 255.0,
120+
g as f32 / 255.0,
121+
b as f32 / 255.0,
122+
a as f32 / 255.0,
123+
)
124+
}
125+
44126
#[inline]
45127
pub fn h(&self) -> f32 {
46128
unsafe { (get_api().godot_color_get_h)(self.sys()) }
@@ -236,6 +318,7 @@ godot_test!(test_color {
236318
assert_eq!("ffffff", Color::from_rgba(1.0, 1.0, 1.0, 0.5).to_html(false).to_string());
237319
assert_eq!("ff8000", Color::from_rgb(1.0, 0.5, 0.0).to_html(false).to_string());
238320
assert_eq!("ff0080ff", Color::from_rgb(0.0, 0.5, 1.0).to_html(true).to_string());
321+
239322
// Test Gray
240323
// String comparison due to non-trivial way to truncate floats
241324
use crate::core_types::IsEqualApprox;

0 commit comments

Comments
 (0)