Change Color HTML conversion from ARGB to RGBA
Also add support for 3 and 4 digit values in C#. Now it actually matches the HTML/CSS spec.
This commit is contained in:
parent
2cfc5b8680
commit
ecd6a893b4
5 changed files with 114 additions and 114 deletions
core
doc/classes
editor/plugins
modules/mono/glue/GodotSharp/GodotSharp/Core
101
core/color.cpp
101
core/color.cpp
|
@ -261,33 +261,21 @@ Color Color::from_rgbe9995(uint32_t p_rgbe) {
|
||||||
return Color(rd, gd, bd, 1.0f);
|
return Color(rd, gd, bd, 1.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
static float _parse_col(const String &p_str, int p_ofs) {
|
static int _parse_col4(const String &p_str, int p_ofs) {
|
||||||
int ig = 0;
|
char character = p_str[p_ofs];
|
||||||
|
|
||||||
for (int i = 0; i < 2; i++) {
|
if (character >= '0' && character <= '9') {
|
||||||
int c = p_str[i + p_ofs];
|
return character - '0';
|
||||||
int v = 0;
|
} else if (character >= 'a' && character <= 'f') {
|
||||||
|
return character + (10 - 'a');
|
||||||
if (c >= '0' && c <= '9') {
|
} else if (character >= 'A' && character <= 'F') {
|
||||||
v = c - '0';
|
return character + (10 - 'A');
|
||||||
} else if (c >= 'a' && c <= 'f') {
|
|
||||||
v = c - 'a';
|
|
||||||
v += 10;
|
|
||||||
} else if (c >= 'A' && c <= 'F') {
|
|
||||||
v = c - 'A';
|
|
||||||
v += 10;
|
|
||||||
} else {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i == 0) {
|
|
||||||
ig += v * 16;
|
|
||||||
} else {
|
|
||||||
ig += v;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
return ig;
|
static int _parse_col8(const String &p_str, int p_ofs) {
|
||||||
|
return _parse_col4(p_str, p_ofs) * 16 + _parse_col4(p_str, p_ofs + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
Color Color::inverted() const {
|
Color Color::inverted() const {
|
||||||
|
@ -302,49 +290,54 @@ Color Color::contrasted() const {
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
Color Color::html(const String &p_color) {
|
Color Color::html(const String &p_rgba) {
|
||||||
String color = p_color;
|
String color = p_rgba;
|
||||||
if (color.length() == 0) {
|
if (color.length() == 0) {
|
||||||
return Color();
|
return Color();
|
||||||
}
|
}
|
||||||
if (color[0] == '#') {
|
if (color[0] == '#') {
|
||||||
color = color.substr(1, color.length() - 1);
|
color = color.substr(1, color.length() - 1);
|
||||||
}
|
}
|
||||||
if (color.length() == 3 || color.length() == 4) {
|
|
||||||
String exp_color;
|
|
||||||
for (int i = 0; i < color.length(); i++) {
|
|
||||||
exp_color += color[i];
|
|
||||||
exp_color += color[i];
|
|
||||||
}
|
|
||||||
color = exp_color;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// If enabled, use 1 hex digit per channel instead of 2.
|
||||||
|
// Other sizes aren't in the HTML/CSS spec but we could add them if desired.
|
||||||
|
bool is_shorthand = color.length() < 5;
|
||||||
bool alpha = false;
|
bool alpha = false;
|
||||||
|
|
||||||
if (color.length() == 8) {
|
if (color.length() == 8) {
|
||||||
alpha = true;
|
alpha = true;
|
||||||
} else if (color.length() == 6) {
|
} else if (color.length() == 6) {
|
||||||
alpha = false;
|
alpha = false;
|
||||||
|
} else if (color.length() == 4) {
|
||||||
|
alpha = true;
|
||||||
|
} else if (color.length() == 3) {
|
||||||
|
alpha = false;
|
||||||
} else {
|
} else {
|
||||||
ERR_FAIL_V_MSG(Color(), "Invalid color code: " + p_color + ".");
|
ERR_FAIL_V_MSG(Color(), "Invalid color code: " + p_rgba + ".");
|
||||||
}
|
}
|
||||||
|
|
||||||
int a = 255;
|
float r, g, b, a = 1.0;
|
||||||
if (alpha) {
|
if (is_shorthand) {
|
||||||
a = _parse_col(color, 0);
|
r = _parse_col4(color, 0) / 15.0;
|
||||||
ERR_FAIL_COND_V_MSG(a < 0, Color(), "Invalid color code: " + p_color + ".");
|
g = _parse_col4(color, 1) / 15.0;
|
||||||
|
b = _parse_col4(color, 2) / 15.0;
|
||||||
|
if (alpha) {
|
||||||
|
a = _parse_col4(color, 3) / 15.0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
r = _parse_col8(color, 0) / 255.0;
|
||||||
|
g = _parse_col8(color, 2) / 255.0;
|
||||||
|
b = _parse_col8(color, 4) / 255.0;
|
||||||
|
if (alpha) {
|
||||||
|
a = _parse_col8(color, 6) / 255.0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
ERR_FAIL_COND_V_MSG(r < 0, Color(), "Invalid color code: " + p_rgba + ".");
|
||||||
|
ERR_FAIL_COND_V_MSG(g < 0, Color(), "Invalid color code: " + p_rgba + ".");
|
||||||
|
ERR_FAIL_COND_V_MSG(b < 0, Color(), "Invalid color code: " + p_rgba + ".");
|
||||||
|
ERR_FAIL_COND_V_MSG(a < 0, Color(), "Invalid color code: " + p_rgba + ".");
|
||||||
|
|
||||||
int from = alpha ? 2 : 0;
|
return Color(r, g, b, a);
|
||||||
|
|
||||||
int r = _parse_col(color, from + 0);
|
|
||||||
ERR_FAIL_COND_V_MSG(r < 0, Color(), "Invalid color code: " + p_color + ".");
|
|
||||||
int g = _parse_col(color, from + 2);
|
|
||||||
ERR_FAIL_COND_V_MSG(g < 0, Color(), "Invalid color code: " + p_color + ".");
|
|
||||||
int b = _parse_col(color, from + 4);
|
|
||||||
ERR_FAIL_COND_V_MSG(b < 0, Color(), "Invalid color code: " + p_color + ".");
|
|
||||||
|
|
||||||
return Color(r / 255.0, g / 255.0, b / 255.0, a / 255.0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Color::html_is_valid(const String &p_color) {
|
bool Color::html_is_valid(const String &p_color) {
|
||||||
|
@ -368,7 +361,7 @@ bool Color::html_is_valid(const String &p_color) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (alpha) {
|
if (alpha) {
|
||||||
int a = _parse_col(color, 0);
|
int a = _parse_col8(color, 0);
|
||||||
if (a < 0) {
|
if (a < 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -376,15 +369,15 @@ bool Color::html_is_valid(const String &p_color) {
|
||||||
|
|
||||||
int from = alpha ? 2 : 0;
|
int from = alpha ? 2 : 0;
|
||||||
|
|
||||||
int r = _parse_col(color, from + 0);
|
int r = _parse_col8(color, from + 0);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
int g = _parse_col(color, from + 2);
|
int g = _parse_col8(color, from + 2);
|
||||||
if (g < 0) {
|
if (g < 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
int b = _parse_col(color, from + 4);
|
int b = _parse_col8(color, from + 4);
|
||||||
if (b < 0) {
|
if (b < 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -438,7 +431,7 @@ String Color::to_html(bool p_alpha) const {
|
||||||
txt += _to_hex(g);
|
txt += _to_hex(g);
|
||||||
txt += _to_hex(b);
|
txt += _to_hex(b);
|
||||||
if (p_alpha) {
|
if (p_alpha) {
|
||||||
txt = _to_hex(a) + txt;
|
txt += _to_hex(a);
|
||||||
}
|
}
|
||||||
return txt;
|
return txt;
|
||||||
}
|
}
|
||||||
|
|
|
@ -185,7 +185,7 @@ struct Color {
|
||||||
|
|
||||||
static Color hex(uint32_t p_hex);
|
static Color hex(uint32_t p_hex);
|
||||||
static Color hex64(uint64_t p_hex);
|
static Color hex64(uint64_t p_hex);
|
||||||
static Color html(const String &p_color);
|
static Color html(const String &p_rgba);
|
||||||
static bool html_is_valid(const String &p_color);
|
static bool html_is_valid(const String &p_color);
|
||||||
static Color named(const String &p_name);
|
static Color named(const String &p_name);
|
||||||
String to_html(bool p_alpha = true) const;
|
String to_html(bool p_alpha = true) const;
|
||||||
|
|
|
@ -18,13 +18,21 @@
|
||||||
<argument index="0" name="from" type="String">
|
<argument index="0" name="from" type="String">
|
||||||
</argument>
|
</argument>
|
||||||
<description>
|
<description>
|
||||||
Constructs a color from an HTML hexadecimal color string in ARGB or RGB format. See also [method @GDScript.ColorN].
|
Constructs a color from an HTML hexadecimal color string in RGB or RGBA format. See also [method @GDScript.ColorN].
|
||||||
[codeblock]
|
[codeblock]
|
||||||
# Each of the following creates the same color RGBA(178, 217, 10, 255).
|
# Each of the following creates the same color RGBA(178, 217, 10, 255).
|
||||||
var c1 = Color("#ffb2d90a") # ARGB format with "#".
|
|
||||||
var c2 = Color("ffb2d90a") # ARGB format.
|
|
||||||
var c3 = Color("#b2d90a") # RGB format with "#".
|
var c3 = Color("#b2d90a") # RGB format with "#".
|
||||||
var c4 = Color("b2d90a") # RGB format.
|
var c4 = Color("b2d90a") # RGB format.
|
||||||
|
var c1 = Color("#b2d90aff") # RGBA format with "#".
|
||||||
|
var c2 = Color("b2d90aff") # RGBA format.
|
||||||
|
[/codeblock]
|
||||||
|
You can also use the "web color" short-hand form by only using 3 or 4 digits.
|
||||||
|
[codeblock]
|
||||||
|
# Each of the following creates the same color RGBA(17, 34, 51, 255).
|
||||||
|
var c3 = Color("#123") # RGB format with "#".
|
||||||
|
var c4 = Color("123") # RGB format.
|
||||||
|
var c1 = Color("#123f") # RGBA format with "#".
|
||||||
|
var c2 = Color("123f") # RGBA format.
|
||||||
[/codeblock]
|
[/codeblock]
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
|
@ -243,11 +251,11 @@
|
||||||
<argument index="0" name="with_alpha" type="bool" default="true">
|
<argument index="0" name="with_alpha" type="bool" default="true">
|
||||||
</argument>
|
</argument>
|
||||||
<description>
|
<description>
|
||||||
Returns the color's HTML hexadecimal color string in ARGB format (ex: [code]ff34f822[/code]).
|
Returns the color's HTML hexadecimal color string in RGBA format (ex: [code]ff34f822[/code]).
|
||||||
Setting [code]with_alpha[/code] to [code]false[/code] excludes alpha from the hexadecimal string.
|
Setting [code]with_alpha[/code] to [code]false[/code] excludes alpha from the hexadecimal string (and uses RGB instead of RGBA format).
|
||||||
[codeblock]
|
[codeblock]
|
||||||
var c = Color(1, 1, 1, 0.5)
|
var c = Color(1, 1, 1, 0.5)
|
||||||
var s1 = c.to_html() # Returns "7fffffff"
|
var s1 = c.to_html() # Returns "ffffff7f"
|
||||||
var s2 = c.to_html(false) # Returns "ffffff"
|
var s2 = c.to_html(false) # Returns "ffffff"
|
||||||
[/codeblock]
|
[/codeblock]
|
||||||
</description>
|
</description>
|
||||||
|
|
|
@ -206,8 +206,8 @@ void ThemeEditor::_save_template_cbk(String fname) {
|
||||||
file->store_line("; [value] examples:");
|
file->store_line("; [value] examples:");
|
||||||
file->store_line("; ");
|
file->store_line("; ");
|
||||||
file->store_line("; Type.item = 6 ; numeric constant. ");
|
file->store_line("; Type.item = 6 ; numeric constant. ");
|
||||||
file->store_line("; Type.item = #FF00FF ; HTML color ");
|
file->store_line("; Type.item = #FF00FF ; HTML color (magenta).");
|
||||||
file->store_line("; Type.item = #55FF00FF ; HTML color with alpha 55.");
|
file->store_line("; Type.item = #FF00FF55 ; HTML color (magenta with alpha 0x55).");
|
||||||
file->store_line("; Type.item = icon(image.png) ; icon in a png file (relative to theme file).");
|
file->store_line("; Type.item = icon(image.png) ; icon in a png file (relative to theme file).");
|
||||||
file->store_line("; Type.item = font(font.xres) ; font in a resource (relative to theme file).");
|
file->store_line("; Type.item = font(font.xres) ; font in a resource (relative to theme file).");
|
||||||
file->store_line("; Type.item = sbox(stylebox.xres) ; stylebox in a resource (relative to theme file).");
|
file->store_line("; Type.item = sbox(stylebox.xres) ; stylebox in a resource (relative to theme file).");
|
||||||
|
|
|
@ -565,6 +565,9 @@ namespace Godot
|
||||||
rgba = rgba.Substring(1);
|
rgba = rgba.Substring(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If enabled, use 1 hex digit per channel instead of 2.
|
||||||
|
// Other sizes aren't in the HTML/CSS spec but we could add them if desired.
|
||||||
|
bool isShorthand = rgba.Length < 5;
|
||||||
bool alpha;
|
bool alpha;
|
||||||
|
|
||||||
if (rgba.Length == 8)
|
if (rgba.Length == 8)
|
||||||
|
@ -575,47 +578,60 @@ namespace Godot
|
||||||
{
|
{
|
||||||
alpha = false;
|
alpha = false;
|
||||||
}
|
}
|
||||||
|
else if (rgba.Length == 4)
|
||||||
|
{
|
||||||
|
alpha = true;
|
||||||
|
}
|
||||||
|
else if (rgba.Length == 3)
|
||||||
|
{
|
||||||
|
alpha = false;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
throw new ArgumentOutOfRangeException("Invalid color code. Length is " + rgba.Length + " but a length of 6 or 8 is expected: " + rgba);
|
throw new ArgumentOutOfRangeException("Invalid color code. Length is " + rgba.Length + " but a length of 6 or 8 is expected: " + rgba);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (alpha)
|
a = 1.0f;
|
||||||
|
if (isShorthand)
|
||||||
{
|
{
|
||||||
a = ParseCol8(rgba, 6) / 255f;
|
r = ParseCol4(rgba, 0) / 15f;
|
||||||
|
g = ParseCol4(rgba, 1) / 15f;
|
||||||
if (a < 0)
|
b = ParseCol4(rgba, 2) / 15f;
|
||||||
|
if (alpha)
|
||||||
{
|
{
|
||||||
throw new ArgumentOutOfRangeException("Invalid color code. Alpha part is not valid hexadecimal: " + rgba);
|
a = ParseCol4(rgba, 3) / 15f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
a = 1.0f;
|
r = ParseCol8(rgba, 0) / 255f;
|
||||||
|
g = ParseCol8(rgba, 2) / 255f;
|
||||||
|
b = ParseCol8(rgba, 4) / 255f;
|
||||||
|
if (alpha)
|
||||||
|
{
|
||||||
|
a = ParseCol8(rgba, 6) / 255f;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int from = alpha ? 2 : 0;
|
|
||||||
|
|
||||||
r = ParseCol8(rgba, 0) / 255f;
|
|
||||||
|
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
{
|
{
|
||||||
throw new ArgumentOutOfRangeException("Invalid color code. Red part is not valid hexadecimal: " + rgba);
|
throw new ArgumentOutOfRangeException("Invalid color code. Red part is not valid hexadecimal: " + rgba);
|
||||||
}
|
}
|
||||||
|
|
||||||
g = ParseCol8(rgba, 2) / 255f;
|
|
||||||
|
|
||||||
if (g < 0)
|
if (g < 0)
|
||||||
{
|
{
|
||||||
throw new ArgumentOutOfRangeException("Invalid color code. Green part is not valid hexadecimal: " + rgba);
|
throw new ArgumentOutOfRangeException("Invalid color code. Green part is not valid hexadecimal: " + rgba);
|
||||||
}
|
}
|
||||||
|
|
||||||
b = ParseCol8(rgba, 4) / 255f;
|
|
||||||
|
|
||||||
if (b < 0)
|
if (b < 0)
|
||||||
{
|
{
|
||||||
throw new ArgumentOutOfRangeException("Invalid color code. Blue part is not valid hexadecimal: " + rgba);
|
throw new ArgumentOutOfRangeException("Invalid color code. Blue part is not valid hexadecimal: " + rgba);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (a < 0)
|
||||||
|
{
|
||||||
|
throw new ArgumentOutOfRangeException("Invalid color code. Alpha part is not valid hexadecimal: " + rgba);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -751,45 +767,28 @@ namespace Godot
|
||||||
value = max;
|
value = max;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static int ParseCol4(string str, int ofs)
|
||||||
|
{
|
||||||
|
char character = str[ofs];
|
||||||
|
|
||||||
|
if (character >= '0' && character <= '9')
|
||||||
|
{
|
||||||
|
return character - '0';
|
||||||
|
}
|
||||||
|
else if (character >= 'a' && character <= 'f')
|
||||||
|
{
|
||||||
|
return character + (10 - 'a');
|
||||||
|
}
|
||||||
|
else if (character >= 'A' && character <= 'F')
|
||||||
|
{
|
||||||
|
return character + (10 - 'A');
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
private static int ParseCol8(string str, int ofs)
|
private static int ParseCol8(string str, int ofs)
|
||||||
{
|
{
|
||||||
int ig = 0;
|
return ParseCol4(str, ofs) * 16 + ParseCol4(str, ofs + 1);
|
||||||
|
|
||||||
for (int i = 0; i < 2; i++)
|
|
||||||
{
|
|
||||||
int c = str[i + ofs];
|
|
||||||
int v;
|
|
||||||
|
|
||||||
if (c >= '0' && c <= '9')
|
|
||||||
{
|
|
||||||
v = c - '0';
|
|
||||||
}
|
|
||||||
else if (c >= 'a' && c <= 'f')
|
|
||||||
{
|
|
||||||
v = c - 'a';
|
|
||||||
v += 10;
|
|
||||||
}
|
|
||||||
else if (c >= 'A' && c <= 'F')
|
|
||||||
{
|
|
||||||
v = c - 'A';
|
|
||||||
v += 10;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i == 0)
|
|
||||||
{
|
|
||||||
ig += v * 16;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ig += v;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ig;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private String ToHex32(float val)
|
private String ToHex32(float val)
|
||||||
|
|
Loading…
Reference in a new issue