[C] support more color format in ColorTypeConverter (#784)

* [C] support more color format in ColorTypeConverter

* [C] Parse numbers in InvariantCulture

* more tests
This commit is contained in:
Stephane Delcroix 2017-03-01 19:45:26 +01:00 коммит произвёл Jason Smith
Родитель badc2e0378
Коммит 837929478e
3 изменённых файлов: 271 добавлений и 172 удалений

Просмотреть файл

@ -241,19 +241,34 @@ namespace Xamarin.Forms.Core.UnitTests
}
[Test]
public void TestColorTypeConverter ()
public void TestColorTypeConverter()
{
var converter = new ColorTypeConverter ();
Assert.True (converter.CanConvertFrom (typeof(string)));
Assert.AreEqual (Color.Blue, converter.ConvertFromInvariantString ("Color.Blue"));
Assert.AreEqual (Color.Blue, converter.ConvertFromInvariantString ("Blue"));
Assert.AreEqual (Color.Blue, converter.ConvertFromInvariantString ("#0000ff"));
Assert.AreEqual (Color.Default, converter.ConvertFromInvariantString ("Color.Default"));
Assert.AreEqual (Color.Accent, converter.ConvertFromInvariantString ("Accent"));
var hotpink = Color.FromHex ("#FF69B4");
var converter = new ColorTypeConverter();
Assert.True(converter.CanConvertFrom(typeof(string)));
Assert.AreEqual(Color.Blue, converter.ConvertFromInvariantString("Color.Blue"));
Assert.AreEqual(Color.Blue, converter.ConvertFromInvariantString("Blue"));
Assert.AreEqual(Color.Blue, converter.ConvertFromInvariantString("blue"));
Assert.AreEqual(Color.Blue, converter.ConvertFromInvariantString("#0000ff"));
Assert.AreEqual(Color.Blue, converter.ConvertFromInvariantString("#00f"));
Assert.AreEqual(Color.Blue.MultiplyAlpha(2.0 / 3.0), converter.ConvertFromInvariantString("#a00f"));
Assert.AreEqual(Color.Blue, converter.ConvertFromInvariantString("rgb(0,0, 255)"));
Assert.AreEqual(Color.Blue, converter.ConvertFromInvariantString("rgb(0,0, 300)"));
Assert.AreEqual(Color.Blue, converter.ConvertFromInvariantString("rgb(0,0, 300)"));
Assert.AreEqual(Color.Blue.MultiplyAlpha(.8), converter.ConvertFromInvariantString("rgba(0%,0%, 100%, .8)"));
Assert.AreEqual(Color.Blue, converter.ConvertFromInvariantString("rgb(0%,0%, 110%)"));
Assert.AreEqual(Color.Blue, converter.ConvertFromInvariantString("hsl(240,100%, 50%)"));
Assert.AreEqual(Color.Blue, converter.ConvertFromInvariantString("hsl(240,110%, 50%)"));
Assert.AreEqual(Color.Blue.MultiplyAlpha(.8), converter.ConvertFromInvariantString("hsla(240,100%, 50%, .8)"));
Assert.AreEqual(Color.Default, converter.ConvertFromInvariantString("Color.Default"));
Assert.AreEqual(Color.Accent, converter.ConvertFromInvariantString("Accent"));
var hotpink = Color.FromHex("#FF69B4");
Color.Accent = hotpink;
Assert.AreEqual (Color.Accent, converter.ConvertFromInvariantString ("Accent"));
Assert.Throws<InvalidOperationException> (() => converter.ConvertFromInvariantString (""));
Assert.AreEqual(Color.Accent, converter.ConvertFromInvariantString("Accent"));
Assert.AreEqual(Color.Default, converter.ConvertFromInvariantString("#12345"));
Assert.Throws<InvalidOperationException>(() => converter.ConvertFromInvariantString(""));
Assert.Throws<InvalidOperationException>(() => converter.ConvertFromInvariantString("rgb(0,0,255"));
Assert.Throws<InvalidOperationException>(() => converter.ConvertFromInvariantString("hsl(12, 100%)"));
Assert.Throws<InvalidOperationException>(() => converter.ConvertFromInvariantString("rgba(0,0,255)"));
}
[Test]
@ -262,7 +277,5 @@ namespace Xamarin.Forms.Core.UnitTests
Assert.AreEqual (Color.Default, default(Color));
Assert.AreEqual (Color.Default, new Color ());
}
}
}
}

Просмотреть файл

@ -299,17 +299,20 @@ namespace Xamarin.Forms
public static Color FromHex(string hex)
{
hex = hex.Replace("#", "");
switch (hex.Length)
{
case 3: //#rgb => ffrrggbb
hex = string.Format("ff{0}{1}{2}{3}{4}{5}", hex[0], hex[0], hex[1], hex[1], hex[2], hex[2]);
break;
case 4: //#argb => aarrggbb
hex = string.Format("{0}{1}{2}{3}{4}{5}{6}{7}", hex[0], hex[0], hex[1], hex[1], hex[2], hex[2], hex[3], hex[3]);
break;
case 6: //#rrggbb => ffrrggbb
hex = string.Format("ff{0}", hex);
break;
switch (hex.Length) {
case 3: //#rgb => ffrrggbb
hex = string.Format("ff{0}{1}{2}{3}{4}{5}", hex[0], hex[0], hex[1], hex[1], hex[2], hex[2]);
break;
case 4: //#argb => aarrggbb
hex = string.Format("{0}{1}{2}{3}{4}{5}{6}{7}", hex[0], hex[0], hex[1], hex[1], hex[2], hex[2], hex[3], hex[3]);
break;
case 6: //#rrggbb => ffrrggbb
hex = string.Format("ff{0}", hex);
break;
case 8: //#aarrggbb
break;
default: //everything else will result in unexpected results
return Default;
}
return FromUint(Convert.ToUInt32(hex, 16));
}

Просмотреть файл

@ -1,170 +1,238 @@
using System;
using System.Linq;
using System.Globalization;
namespace Xamarin.Forms
{
[Xaml.ProvideCompiled("Xamarin.Forms.Core.XamlC.ColorTypeConverter")]
public class ColorTypeConverter : TypeConverter
{
// Supported inputs
// HEX #rgb, #argb, #rrggbb, #aarrggbb
// RGB rgb(255,0,0), rgb(100%,0%,0%) values in range 0-255 or 0%-100%
// RGBA rgba(255, 0, 0, 0.8), rgba(100%, 0%, 0%, 0.8) opacity is 0.0-1.0
// HSL hsl(120, 100%, 50%) h is 0-360, s and l are 0%-100%
// HSLA hsla(120, 100%, 50%, .8) opacity is 0.0-1.0
// Predefined color case insensitive
public override object ConvertFromInvariantString(string value)
{
if (value != null)
{
if (value.Trim().StartsWith("#", StringComparison.Ordinal))
value = value.Trim();
if (value.StartsWith("#", StringComparison.Ordinal))
return Color.FromHex(value);
if (value.StartsWith("rgba", StringComparison.OrdinalIgnoreCase)) {
var op = value.IndexOf('(');
var cp = value.LastIndexOf(')');
if (op < 0 || cp < 0 || cp < op)
throw new InvalidOperationException($"Cannot convert \"{value}\" into {typeof(Color)}");
var quad = value.Substring(op + 1, cp - op - 1).Split(',');
if (quad.Length != 4)
throw new InvalidOperationException($"Cannot convert \"{value}\" into {typeof(Color)}");
var r = ParseColorValue(quad[0], 255, acceptPercent: true);
var g = ParseColorValue(quad[1], 255, acceptPercent: true);
var b = ParseColorValue(quad[2], 255, acceptPercent: true);
var a = ParseOpacity(quad[3]);
return new Color(r, g, b, a);
}
if (value.StartsWith("rgb", StringComparison.OrdinalIgnoreCase)) {
var op = value.IndexOf('(');
var cp = value.LastIndexOf(')');
if (op < 0 || cp < 0 || cp < op)
throw new InvalidOperationException($"Cannot convert \"{value}\" into {typeof(Color)}");
var triplet = value.Substring(op + 1, cp - op - 1).Split(',');
if (triplet.Length != 3)
throw new InvalidOperationException($"Cannot convert \"{value}\" into {typeof(Color)}");
var r = ParseColorValue(triplet[0], 255, acceptPercent: true);
var g = ParseColorValue(triplet[1], 255, acceptPercent: true);
var b = ParseColorValue(triplet[2], 255, acceptPercent: true);
return new Color(r, g, b);
}
if (value.StartsWith("hsla", StringComparison.OrdinalIgnoreCase)) {
var op = value.IndexOf('(');
var cp = value.LastIndexOf(')');
if (op < 0 || cp < 0 || cp < op)
throw new InvalidOperationException($"Cannot convert \"{value}\" into {typeof(Color)}");
var quad = value.Substring(op + 1, cp - op - 1).Split(',');
if (quad.Length != 4)
throw new InvalidOperationException($"Cannot convert \"{value}\" into {typeof(Color)}");
var h = ParseColorValue(quad[0], 360, acceptPercent: false);
var s = ParseColorValue(quad[1], 100, acceptPercent: true);
var l = ParseColorValue(quad[2], 100, acceptPercent: true);
var a = ParseOpacity(quad[3]);
return Color.FromHsla(h, s, l, a);
}
if (value.StartsWith("hsl", StringComparison.OrdinalIgnoreCase)) {
var op = value.IndexOf('(');
var cp = value.LastIndexOf(')');
if (op < 0 || cp < 0 || cp < op)
throw new InvalidOperationException($"Cannot convert \"{value}\" into {typeof(Color)}");
var triplet = value.Substring(op + 1, cp - op - 1).Split(',');
if (triplet.Length != 3)
throw new InvalidOperationException($"Cannot convert \"{value}\" into {typeof(Color)}");
var h = ParseColorValue(triplet[0], 360, acceptPercent: false);
var s = ParseColorValue(triplet[1], 100, acceptPercent: true);
var l = ParseColorValue(triplet[2], 100, acceptPercent: true);
return Color.FromHsla(h, s, l);
}
string[] parts = value.Split('.');
if (parts.Length == 1 || (parts.Length == 2 && parts[0] == "Color"))
{
string color = parts[parts.Length - 1];
switch (color) {
case "Default": return Color.Default;
case "Accent": return Color.Accent;
case "AliceBlue": return Color.AliceBlue;
case "AntiqueWhite": return Color.AntiqueWhite;
case "Aqua": return Color.Aqua;
case "Aquamarine": return Color.Aquamarine;
case "Azure": return Color.Azure;
case "Beige": return Color.Beige;
case "Bisque": return Color.Bisque;
case "Black": return Color.Black;
case "BlanchedAlmond": return Color.BlanchedAlmond;
case "Blue": return Color.Blue;
case "BlueViolet": return Color.BlueViolet;
case "Brown": return Color.Brown;
case "BurlyWood": return Color.BurlyWood;
case "CadetBlue": return Color.CadetBlue;
case "Chartreuse": return Color.Chartreuse;
case "Chocolate": return Color.Chocolate;
case "Coral": return Color.Coral;
case "CornflowerBlue": return Color.CornflowerBlue;
case "Cornsilk": return Color.Cornsilk;
case "Crimson": return Color.Crimson;
case "Cyan": return Color.Cyan;
case "DarkBlue": return Color.DarkBlue;
case "DarkCyan": return Color.DarkCyan;
case "DarkGoldenrod": return Color.DarkGoldenrod;
case "DarkGray": return Color.DarkGray;
case "DarkGreen": return Color.DarkGreen;
case "DarkKhaki": return Color.DarkKhaki;
case "DarkMagenta": return Color.DarkMagenta;
case "DarkOliveGreen": return Color.DarkOliveGreen;
case "DarkOrange": return Color.DarkOrange;
case "DarkOrchid": return Color.DarkOrchid;
case "DarkRed": return Color.DarkRed;
case "DarkSalmon": return Color.DarkSalmon;
case "DarkSeaGreen": return Color.DarkSeaGreen;
case "DarkSlateBlue": return Color.DarkSlateBlue;
case "DarkSlateGray": return Color.DarkSlateGray;
case "DarkTurquoise": return Color.DarkTurquoise;
case "DarkViolet": return Color.DarkViolet;
case "DeepPink": return Color.DeepPink;
case "DeepSkyBlue": return Color.DeepSkyBlue;
case "DimGray": return Color.DimGray;
case "DodgerBlue": return Color.DodgerBlue;
case "Firebrick": return Color.Firebrick;
case "FloralWhite": return Color.FloralWhite;
case "ForestGreen": return Color.ForestGreen;
case "Fuchsia": return Color.Fuchsia;
case "Gainsboro": return Color.Gainsboro;
case "GhostWhite": return Color.GhostWhite;
case "Gold": return Color.Gold;
case "Goldenrod": return Color.Goldenrod;
case "Gray": return Color.Gray;
case "Green": return Color.Green;
case "GreenYellow": return Color.GreenYellow;
case "Honeydew": return Color.Honeydew;
case "HotPink": return Color.HotPink;
case "IndianRed": return Color.IndianRed;
case "Indigo": return Color.Indigo;
case "Ivory": return Color.Ivory;
case "Khaki": return Color.Khaki;
case "Lavender": return Color.Lavender;
case "LavenderBlush": return Color.LavenderBlush;
case "LawnGreen": return Color.LawnGreen;
case "LemonChiffon": return Color.LemonChiffon;
case "LightBlue": return Color.LightBlue;
case "LightCoral": return Color.LightCoral;
case "LightCyan": return Color.LightCyan;
case "LightGoldenrodYellow": return Color.LightGoldenrodYellow;
case "LightGray": return Color.LightGray;
case "LightGreen": return Color.LightGreen;
case "LightPink": return Color.LightPink;
case "LightSalmon": return Color.LightSalmon;
case "LightSeaGreen": return Color.LightSeaGreen;
case "LightSkyBlue": return Color.LightSkyBlue;
case "LightSlateGray": return Color.LightSlateGray;
case "LightSteelBlue": return Color.LightSteelBlue;
case "LightYellow": return Color.LightYellow;
case "Lime": return Color.Lime;
case "LimeGreen": return Color.LimeGreen;
case "Linen": return Color.Linen;
case "Magenta": return Color.Magenta;
case "Maroon": return Color.Maroon;
case "MediumAquamarine": return Color.MediumAquamarine;
case "MediumBlue": return Color.MediumBlue;
case "MediumOrchid": return Color.MediumOrchid;
case "MediumPurple": return Color.MediumPurple;
case "MediumSeaGreen": return Color.MediumSeaGreen;
case "MediumSlateBlue": return Color.MediumSlateBlue;
case "MediumSpringGreen": return Color.MediumSpringGreen;
case "MediumTurquoise": return Color.MediumTurquoise;
case "MediumVioletRed": return Color.MediumVioletRed;
case "MidnightBlue": return Color.MidnightBlue;
case "MintCream": return Color.MintCream;
case "MistyRose": return Color.MistyRose;
case "Moccasin": return Color.Moccasin;
case "NavajoWhite": return Color.NavajoWhite;
case "Navy": return Color.Navy;
case "OldLace": return Color.OldLace;
case "Olive": return Color.Olive;
case "OliveDrab": return Color.OliveDrab;
case "Orange": return Color.Orange;
case "OrangeRed": return Color.OrangeRed;
case "Orchid": return Color.Orchid;
case "PaleGoldenrod": return Color.PaleGoldenrod;
case "PaleGreen": return Color.PaleGreen;
case "PaleTurquoise": return Color.PaleTurquoise;
case "PaleVioletRed": return Color.PaleVioletRed;
case "PapayaWhip": return Color.PapayaWhip;
case "PeachPuff": return Color.PeachPuff;
case "Peru": return Color.Peru;
case "Pink": return Color.Pink;
case "Plum": return Color.Plum;
case "PowderBlue": return Color.PowderBlue;
case "Purple": return Color.Purple;
case "Red": return Color.Red;
case "RosyBrown": return Color.RosyBrown;
case "RoyalBlue": return Color.RoyalBlue;
case "SaddleBrown": return Color.SaddleBrown;
case "Salmon": return Color.Salmon;
case "SandyBrown": return Color.SandyBrown;
case "SeaGreen": return Color.SeaGreen;
case "SeaShell": return Color.SeaShell;
case "Sienna": return Color.Sienna;
case "Silver": return Color.Silver;
case "SkyBlue": return Color.SkyBlue;
case "SlateBlue": return Color.SlateBlue;
case "SlateGray": return Color.SlateGray;
case "Snow": return Color.Snow;
case "SpringGreen": return Color.SpringGreen;
case "SteelBlue": return Color.SteelBlue;
case "Tan": return Color.Tan;
case "Teal": return Color.Teal;
case "Thistle": return Color.Thistle;
case "Tomato": return Color.Tomato;
case "Transparent": return Color.Transparent;
case "Turquoise": return Color.Turquoise;
case "Violet": return Color.Violet;
case "Wheat": return Color.Wheat;
case "White": return Color.White;
case "WhiteSmoke": return Color.WhiteSmoke;
case "Yellow": return Color.Yellow;
case "YellowGreen": return Color.YellowGreen;
switch (color.ToLowerInvariant()) {
case "default": return Color.Default;
case "accent": return Color.Accent;
case "aliceblue": return Color.AliceBlue;
case "antiquewhite": return Color.AntiqueWhite;
case "aqua": return Color.Aqua;
case "aquamarine": return Color.Aquamarine;
case "azure": return Color.Azure;
case "beige": return Color.Beige;
case "bisque": return Color.Bisque;
case "black": return Color.Black;
case "blanchedalmond": return Color.BlanchedAlmond;
case "blue": return Color.Blue;
case "blueViolet": return Color.BlueViolet;
case "brown": return Color.Brown;
case "burlywood": return Color.BurlyWood;
case "cadetblue": return Color.CadetBlue;
case "chartreuse": return Color.Chartreuse;
case "chocolate": return Color.Chocolate;
case "coral": return Color.Coral;
case "cornflowerblue": return Color.CornflowerBlue;
case "cornsilk": return Color.Cornsilk;
case "crimson": return Color.Crimson;
case "cyan": return Color.Cyan;
case "darkblue": return Color.DarkBlue;
case "darkcyan": return Color.DarkCyan;
case "darkgoldenrod": return Color.DarkGoldenrod;
case "darkgray": return Color.DarkGray;
case "darkgreen": return Color.DarkGreen;
case "darkkhaki": return Color.DarkKhaki;
case "darkmagenta": return Color.DarkMagenta;
case "darkolivegreen": return Color.DarkOliveGreen;
case "darkorange": return Color.DarkOrange;
case "darkorchid": return Color.DarkOrchid;
case "darkred": return Color.DarkRed;
case "darksalmon": return Color.DarkSalmon;
case "darkseagreen": return Color.DarkSeaGreen;
case "darkslateblue": return Color.DarkSlateBlue;
case "darkslategray": return Color.DarkSlateGray;
case "darkturquoise": return Color.DarkTurquoise;
case "darkviolet": return Color.DarkViolet;
case "deeppink": return Color.DeepPink;
case "deepskyblue": return Color.DeepSkyBlue;
case "dimgray": return Color.DimGray;
case "dodgerblue": return Color.DodgerBlue;
case "firebrick": return Color.Firebrick;
case "floralwhite": return Color.FloralWhite;
case "forestgreen": return Color.ForestGreen;
case "fuchsia": return Color.Fuchsia;
case "gainsboro": return Color.Gainsboro;
case "ghostwhite": return Color.GhostWhite;
case "gold": return Color.Gold;
case "goldenrod": return Color.Goldenrod;
case "gray": return Color.Gray;
case "green": return Color.Green;
case "greenyellow": return Color.GreenYellow;
case "honeydew": return Color.Honeydew;
case "hotpink": return Color.HotPink;
case "indianred": return Color.IndianRed;
case "indigo": return Color.Indigo;
case "ivory": return Color.Ivory;
case "khaki": return Color.Khaki;
case "lavender": return Color.Lavender;
case "lavenderblush": return Color.LavenderBlush;
case "lawngreen": return Color.LawnGreen;
case "lemonchiffon": return Color.LemonChiffon;
case "lightblue": return Color.LightBlue;
case "lightcoral": return Color.LightCoral;
case "lightcyan": return Color.LightCyan;
case "lightgoldenrodyellow": return Color.LightGoldenrodYellow;
case "lightgray": return Color.LightGray;
case "lightgreen": return Color.LightGreen;
case "lightpink": return Color.LightPink;
case "lightsalmon": return Color.LightSalmon;
case "lightseagreen": return Color.LightSeaGreen;
case "lightskyblue": return Color.LightSkyBlue;
case "lightslategray": return Color.LightSlateGray;
case "lightsteelblue": return Color.LightSteelBlue;
case "lightyellow": return Color.LightYellow;
case "lime": return Color.Lime;
case "limegreen": return Color.LimeGreen;
case "linen": return Color.Linen;
case "magenta": return Color.Magenta;
case "maroon": return Color.Maroon;
case "mediumaquamarine": return Color.MediumAquamarine;
case "mediumblue": return Color.MediumBlue;
case "mediumorchid": return Color.MediumOrchid;
case "mediumpurple": return Color.MediumPurple;
case "mediumseagreen": return Color.MediumSeaGreen;
case "mediumslateblue": return Color.MediumSlateBlue;
case "mediumspringgreen": return Color.MediumSpringGreen;
case "mediumturquoise": return Color.MediumTurquoise;
case "mediumvioletred": return Color.MediumVioletRed;
case "midnightblue": return Color.MidnightBlue;
case "mintcream": return Color.MintCream;
case "mistyrose": return Color.MistyRose;
case "moccasin": return Color.Moccasin;
case "navajowhite": return Color.NavajoWhite;
case "navy": return Color.Navy;
case "oldlace": return Color.OldLace;
case "olive": return Color.Olive;
case "olivedrab": return Color.OliveDrab;
case "orange": return Color.Orange;
case "orangered": return Color.OrangeRed;
case "orchid": return Color.Orchid;
case "palegoldenrod": return Color.PaleGoldenrod;
case "palegreen": return Color.PaleGreen;
case "paleturquoise": return Color.PaleTurquoise;
case "palevioletred": return Color.PaleVioletRed;
case "papayawhip": return Color.PapayaWhip;
case "peachpuff": return Color.PeachPuff;
case "peru": return Color.Peru;
case "pink": return Color.Pink;
case "plum": return Color.Plum;
case "powderblue": return Color.PowderBlue;
case "purple": return Color.Purple;
case "red": return Color.Red;
case "rosybrown": return Color.RosyBrown;
case "royalblue": return Color.RoyalBlue;
case "saddlebrown": return Color.SaddleBrown;
case "salmon": return Color.Salmon;
case "sandybrown": return Color.SandyBrown;
case "seagreen": return Color.SeaGreen;
case "seashell": return Color.SeaShell;
case "sienna": return Color.Sienna;
case "silver": return Color.Silver;
case "skyblue": return Color.SkyBlue;
case "slateblue": return Color.SlateBlue;
case "slategray": return Color.SlateGray;
case "snow": return Color.Snow;
case "springgreen": return Color.SpringGreen;
case "steelblue": return Color.SteelBlue;
case "tan": return Color.Tan;
case "teal": return Color.Teal;
case "thistle": return Color.Thistle;
case "tomato": return Color.Tomato;
case "transparent": return Color.Transparent;
case "turquoise": return Color.Turquoise;
case "violet": return Color.Violet;
case "wheat": return Color.Wheat;
case "white": return Color.White;
case "whitesmoke": return Color.WhiteSmoke;
case "yellow": return Color.Yellow;
case "yellowgreen": return Color.YellowGreen;
}
var field = typeof(Color).GetFields().FirstOrDefault(fi => fi.IsStatic && fi.Name == color);
var field = typeof(Color).GetFields().FirstOrDefault(fi => fi.IsStatic && string.Equals(fi.Name, color, StringComparison.OrdinalIgnoreCase));
if (field != null)
return (Color)field.GetValue(null);
var property = typeof(Color).GetProperties().FirstOrDefault(pi => pi.Name == color && pi.CanRead && pi.GetMethod.IsStatic);
var property = typeof(Color).GetProperties().FirstOrDefault(pi => string.Equals(pi.Name, color, StringComparison.OrdinalIgnoreCase) && pi.CanRead && pi.GetMethod.IsStatic);
if (property != null)
return (Color)property.GetValue(null, null);
}
@ -172,5 +240,20 @@ namespace Xamarin.Forms
throw new InvalidOperationException($"Cannot convert \"{value}\" into {typeof(Color)}");
}
static double ParseColorValue(string elem, int maxValue, bool acceptPercent)
{
elem = elem.Trim();
if (elem.EndsWith("%", StringComparison.Ordinal) && acceptPercent) {
maxValue = 100;
elem = elem.Substring(0, elem.Length - 1);
}
return (double)(int.Parse(elem, NumberStyles.Number, CultureInfo.InvariantCulture).Clamp(0, maxValue)) / maxValue;
}
static double ParseOpacity(string elem)
{
return double.Parse(elem, NumberStyles.Number, CultureInfo.InvariantCulture).Clamp(0, 1);
}
}
}