svn path=/branches/mono-1-1-9/mcs/; revision=51206
[mono.git] / mcs / class / System.Web / System.Web.UI.WebControls / Unit.cs
1 //
2 // System.Web.UI.WebControls.Unit.cs
3 //
4 // Authors:
5 //   Miguel de Icaza (miguel@novell.com)
6 //   Ben Maurer (bmaurer@ximian.com).
7 //
8 // (C) 2005 Novell, Inc.
9 //
10
11 //
12 // Permission is hereby granted, free of charge, to any person obtaining
13 // a copy of this software and associated documentation files (the
14 // "Software"), to deal in the Software without restriction, including
15 // without limitation the rights to use, copy, modify, merge, publish,
16 // distribute, sublicense, and/or sell copies of the Software, and to
17 // permit persons to whom the Software is furnished to do so, subject to
18 // the following conditions:
19 // 
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
22 // 
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 //
31
32 using System;
33 using System.Globalization;
34 using System.ComponentModel;
35
36 namespace System.Web.UI.WebControls {
37
38         [TypeConverter(typeof (UnitConverter))]
39 #if NET_2_0
40         [Serializable]
41 #endif
42         public struct Unit {
43                 UnitType type;
44                 double value;
45                 public static readonly Unit Empty;
46                 
47                 public Unit (double value, UnitType type)
48                 {
49                         if (value < -32768 || value > 32767)
50                                 throw new ArgumentOutOfRangeException ("value");
51
52                         this.type = type;
53                         if (type == UnitType.Pixel)
54                                 this.value = (int) value;
55                         else
56                                 this.value = value;
57                 }
58
59                 public Unit (double value) : this (value, UnitType.Pixel)
60                 {
61                 }
62                 
63                 public Unit (int value) : this ((double) value, UnitType.Pixel)
64                 {
65                 }
66
67                 internal Unit (string value, char sep)
68                 {
69                         if (value == null || value == String.Empty){
70                                 type = (UnitType) 0;
71                                 this.value = 0.0;
72                                 return;
73                         }
74
75                         int count = value.Length;
76                         int i = 0;
77                         int sign = 1;
78                         
79                         while (i < count && Char.IsWhiteSpace (value [i]))
80                                 i++;
81                         if (value [i] == '-'){
82                                 sign = -1;
83                                 i++;
84                                 if (!Char.IsDigit (value [i]))
85                                         throw new ArgumentOutOfRangeException ("value");
86                         } else if (!Char.IsDigit (value [i])) {
87                                 throw new FormatException ();
88                         }
89
90                         double dv = 0;
91                         for (; i < count; i++){
92                                 char c = value [i];
93                                 if (!Char.IsDigit (c))
94                                         break;
95                                 dv = dv * 10 + ((int) c) - ((int) '0');
96                         }
97                         dv *= sign;
98                         this.value = dv;
99                         dv = 0;
100                         if (i < count && value [i] == sep){
101                                 i++;
102                                 double factor = .1;
103                                 for (; i < count; i++){
104                                         char c = value [i];
105                                         if (!Char.IsDigit (c))
106                                                 break;
107                                         dv = dv + (((int) c) - ((int) '0')) * factor;
108                                         factor = factor *.1;
109                                 }
110                                 this.value += dv;
111                         }
112                         
113                         while (i < count && Char.IsWhiteSpace (value [i]))
114                                 i++;
115
116                         if (i == count){
117                                 type = UnitType.Pixel;
118                                 return;
119                         }
120
121                         if (value [i] == '%'){
122                                 type = UnitType.Percentage;
123                                 i++;
124                                 while (i < count && Char.IsWhiteSpace (value [i]))
125                                         i++;
126                                 if (i != count)
127                                         throw new ArgumentOutOfRangeException ("value");
128                                 return;
129                         }
130                         
131                         int j = i;
132                         while (j < count && Char.IsLetter (value [j]))
133                                 j++;
134                         string code = value.Substring (i, j-i);
135                         switch (code.ToLower (CultureInfo.InvariantCulture)){
136                         case "in": type = UnitType.Inch; break;
137                         case "cm": type = UnitType.Cm; break;
138                         case "mm": type = UnitType.Mm; break;
139                         case "pt": type = UnitType.Point; break;
140                         case "pc": type = UnitType.Pica; break;
141                         case "em": type = UnitType.Em; break;
142                         case "ex": type = UnitType.Ex; break;
143                         case "px":
144                                 type = UnitType.Pixel;
145                                 if (dv != 0)
146                                         throw new FormatException ("Pixel units do not allow floating point values");
147                                 break;
148                         default:
149                                 throw new ArgumentOutOfRangeException ("value");
150                         }
151
152                         while (j < count && Char.IsWhiteSpace (value [j]))
153                                 j++;
154                         if (j != count)
155                                 throw new ArgumentOutOfRangeException ("value");
156                 }
157
158                 
159                 public Unit (string value) : this (value, '.')
160                 {
161                 }
162
163                 public Unit (string value, CultureInfo culture) : this (value, culture.NumberFormat.NumberDecimalSeparator [0])
164                 {
165                 }
166
167                 internal Unit (string value, CultureInfo culture, UnitType t) : this (value, '.')
168                 {
169                 }
170                 
171                 public bool IsEmpty {
172                         get {
173                                 return type == 0;
174                         }
175                 }
176
177                 public UnitType Type {
178                         get {
179                                 if (type == 0)
180                                         return UnitType.Pixel;
181                                 return type;
182                         }
183                 }
184
185                 public double Value {
186                         get {
187                                 return value;
188                         }
189                 }
190                 
191                 public static Unit Parse (string s)
192                 {
193                         return new Unit (s);
194                 }
195
196                 public static System.Web.UI.WebControls.Unit Parse (string s, System.Globalization.CultureInfo culture)
197                 {
198                         return new Unit (s, culture);
199                 }
200                 
201
202                 public static Unit Percentage (double n)
203                 {
204                         return new Unit (n, UnitType.Percentage);
205                 }
206                 
207                 public static Unit Pixel (int n)
208                 {
209                         return new Unit (n);
210                 }
211                 
212                 public static Unit Point (int n)
213                 {
214                         return new Unit (n, UnitType.Point);
215                 }
216                                 
217                 public override bool Equals (object obj)
218                 {
219                         if (obj is Unit){
220                                 Unit other = (Unit) obj;
221                                 return (other.type == type && other.value == value);
222                         }
223                         return false;
224                 }
225                 
226                 public override int GetHashCode ()
227                 {
228                         return Type.GetHashCode () ^ Value.GetHashCode ();
229                 }
230                 
231                 public static bool operator == (Unit left, Unit right)
232                 {
233                         return left.Type == right.Type && left.Value == right.Value;
234                 }
235
236                 public static bool operator != (Unit left, Unit right)
237                 {
238                         return left.Type != right.Type || left.Value != right.Value;
239                 }
240                 
241                 public static implicit operator Unit (int n)
242                 {
243                         return new Unit (n);
244                 }
245
246                 string GetExtension ()
247                 {
248                         switch (type){
249                         case UnitType.Pixel: return "px";
250                         case UnitType.Point: return "pt";
251                         case UnitType.Pica: return "pc";
252                         case UnitType.Inch: return "in";
253                         case UnitType.Mm: return "mm";
254                         case UnitType.Cm: return "cm";
255                         case UnitType.Percentage: return "%";
256                         case UnitType.Em: return "em";
257                         case UnitType.Ex: return "ex";
258                         default: return "";
259                         }
260                 }
261
262                 public string ToString (CultureInfo culture)
263                 {
264                         if (type == 0)
265                                 return "";
266                         
267                         string ex = GetExtension ();
268                         
269                         return String.Format (culture, "{0}{1}", value, ex);
270                 }
271                         
272                 public override string ToString ()
273                 {
274                         return ToString (CultureInfo.InvariantCulture);
275                 }
276
277 #if NET_2_0
278                 public string ToString (IFormatProvider provider)
279                 {
280                         if (type == 0)
281                                 return "";
282
283                         string ex = GetExtension ();
284
285                         return String.Format (provider, "{0}{1}", value, ex);
286                 }
287 #endif
288         }
289
290 }