2 // System.Drawing.ColorConverter
5 // Gonzalo Paniagua Javier (gonzalo@ximian.com)
6 // Ravindra (rkumar@novell.com)
8 // Copyright (C) 2002 Ximian, Inc. http://www.ximian.com
9 // Copyright (C) 2004,2006 Novell, Inc (http://www.novell.com)
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 using System.Collections;
32 using System.ComponentModel;
33 using System.Globalization;
35 using System.ComponentModel.Design.Serialization;
36 using System.Reflection;
38 namespace System.Drawing
40 public class ColorConverter : TypeConverter
42 static StandardValuesCollection cached;
43 static object creatingCached = new object ();
45 public ColorConverter () { }
47 public override bool CanConvertFrom (ITypeDescriptorContext context, Type sourceType)
49 if (sourceType == typeof (string))
52 return base.CanConvertFrom (context, sourceType);
55 public override bool CanConvertTo (ITypeDescriptorContext context, Type destinationType)
57 if (destinationType == typeof (InstanceDescriptor))
60 return base.CanConvertTo (context, destinationType);
63 internal static Color StaticConvertFromString (ITypeDescriptorContext context, string s, CultureInfo culture)
66 culture = CultureInfo.InvariantCulture;
73 // Try to process both NamedColor and SystemColors from the KnownColor enumeration
74 if (Char.IsLetter (s [0])) {
77 kc = (KnownColor) Enum.Parse (typeof (KnownColor), s, true);
80 // whatever happens MS throws an basic Exception
81 string msg = Locale.GetText ("Invalid color name '{0}'.", s);
82 throw new Exception (msg, new FormatException (msg, e));
84 return KnownColors.FromKnownColor (kc);
87 String numSeparator = culture.TextInfo.ListSeparator;
88 Color result = Color.Empty;
90 if (s.IndexOf (numSeparator) == -1) {
91 bool sharp = (s[0] == '#');
92 int start = sharp ? 1 : 0;
94 // deal with #hex, 0xhex and #0xhex
95 if ((s.Length > start + 1) && (s[start] == '0')) {
96 hex = ((s[start + 1] == 'x') || (s[start + 1] == 'X'));
102 s = s.Substring (start);
105 argb = Int32.Parse (s, NumberStyles.HexNumber);
107 catch (Exception e) {
108 // whatever happens MS throws an basic Exception
109 string msg = Locale.GetText ("Invalid Int32 value '{0}'.", s);
110 throw new Exception (msg, e);
113 // note that the default alpha value for a 6 hex digit (i.e. when none are present) is
114 // 0xFF while shorter string defaults to 0xFF - unless both # an 0x are specified
115 if ((s.Length < 6) || ((s.Length == 6) && sharp && hex))
117 else if ((argb >> 24) == 0)
118 argb |= unchecked((int)0xFF000000);
119 result = Color.FromArgb (argb);
123 if (result.IsEmpty) {
124 Int32Converter converter = new Int32Converter ();
125 String [] components = s.Split (numSeparator.ToCharArray ());
127 // MS seems to convert the indivual component to int before
128 // checking the number of components
129 int[] numComponents = new int[components.Length];
130 for (int i = 0; i < numComponents.Length; i++) {
131 numComponents[i] = (int) converter.ConvertFrom (context,
132 culture, components[i]);
135 switch (components.Length) {
137 result = Color.FromArgb (numComponents[0]);
140 result = Color.FromArgb (numComponents[0], numComponents[1],
144 result = Color.FromArgb (numComponents[0], numComponents[1],
145 numComponents[2], numComponents[3]);
148 throw new ArgumentException (s + " is not a valid color value.");
152 if (!result.IsEmpty) {
153 // Look for a named or system color with those values
154 Color known = KnownColors.FindColorMatch (result);
163 public override object ConvertFrom (ITypeDescriptorContext context,
167 string s = value as string;
169 return base.ConvertFrom (context, culture, value);
171 return StaticConvertFromString (context, s, culture);
174 public override object ConvertTo (ITypeDescriptorContext context,
177 Type destinationType)
179 if ((destinationType == typeof (string)) && (value is Color)) {
180 Color color = (Color) value;
182 if (color == Color.Empty) {
186 if (color.IsKnownColor || color.IsNamedColor)
189 String numSeparator = culture.TextInfo.ListSeparator;
191 StringBuilder sb = new StringBuilder ();
192 if (color.A != 255) {
194 sb.Append (numSeparator);
198 sb.Append (numSeparator);
202 sb.Append (numSeparator);
206 return sb.ToString ();
209 if (destinationType == typeof (InstanceDescriptor) && value is Color) {
210 Color c = (Color)value;
212 return new InstanceDescriptor (typeof (Color).GetField ("Empty"), null);
213 } else if (c.IsSystemColor) {
214 return new InstanceDescriptor (typeof (SystemColors).GetProperty (c.Name), null);
215 } else if (c.IsKnownColor){
216 return new InstanceDescriptor (typeof (Color).GetProperty (c.Name), null);
218 MethodInfo met = typeof(Color).GetMethod ("FromArgb", new Type[] { typeof(int), typeof(int), typeof(int), typeof(int) } );
219 return new InstanceDescriptor (met, new object[] {c.A, c.R, c.G, c.B });
223 return base.ConvertTo (context, culture, value, destinationType);
226 public override StandardValuesCollection GetStandardValues (ITypeDescriptorContext context)
228 lock (creatingCached) {
232 Color [] colors = new Color [KnownColors.Values.Length - 1];
233 Array.Copy (KnownColors.Values, 1, colors, 0, colors.Length);
235 Array colors = Array.CreateInstance (typeof (Color), KnownColors.ArgbValues.Length - 1);
236 for (int i=1; i < KnownColors.ArgbValues.Length; i++) {
237 colors.SetValue (KnownColors.FromKnownColor ((KnownColor)i), i - 1);
241 Array.Sort (colors, 0, colors.Length, new CompareColors ());
242 cached = new StandardValuesCollection (colors);
248 public override bool GetStandardValuesSupported (ITypeDescriptorContext context)
253 sealed class CompareColors : IComparer {
255 public int Compare (object x, object y)
257 return String.Compare (((Color) x).Name, ((Color) y).Name);