2005-07-27 Miguel de Icaza <miguel@novell.com>
[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                         }
87
88                         double dv = 0;
89                         for (; i < count; i++){
90                                 char c = value [i];
91                                 if (!Char.IsDigit (c))
92                                         break;
93                                 dv = dv * 10 + ((int) c) - ((int) '0');
94                         }
95                         dv *= sign;
96                         this.value = dv;
97                         dv = 0;
98                         if (i < count && value [i] == sep){
99                                 i++;
100                                 double factor = .1;
101                                 for (; i < count; i++){
102                                         char c = value [i];
103                                         if (!Char.IsDigit (c))
104                                                 break;
105                                         dv = dv + (((int) c) - ((int) '0')) * factor;
106                                         factor = factor *.1;
107                                 }
108                                 this.value += dv;
109                         }
110                         
111                         while (i < count && Char.IsWhiteSpace (value [i]))
112                                 i++;
113
114                         if (i == count){
115                                 type = UnitType.Pixel;
116                                 return;
117                         }
118
119                         if (value [i] == '%'){
120                                 type = UnitType.Percentage;
121                                 i++;
122                                 while (i < count && Char.IsWhiteSpace (value [i]))
123                                         i++;
124                                 if (i != count)
125                                         throw new ArgumentOutOfRangeException ("value");
126                                 return;
127                         }
128                         
129                         int j = i;
130                         while (j < count && Char.IsLetter (value [j]))
131                                 j++;
132                         string code = value.Substring (i, j-i);
133                         switch (code.ToLower (CultureInfo.InvariantCulture)){
134                         case "in": type = UnitType.Inch; break;
135                         case "cm": type = UnitType.Cm; break;
136                         case "mm": type = UnitType.Mm; break;
137                         case "pt": type = UnitType.Point; break;
138                         case "pc": type = UnitType.Pica; break;
139                         case "em": type = UnitType.Em; break;
140                         case "ex": type = UnitType.Ex; break;
141                         case "px":
142                                 type = UnitType.Pixel;
143                                 if (dv != 0)
144                                         throw new FormatException ("Pixel units do not allow floating point values");
145                                 break;
146                         default:
147                                 throw new ArgumentOutOfRangeException ("value");
148                         }
149
150                         while (j < count && Char.IsWhiteSpace (value [j]))
151                                 j++;
152                         if (j != count)
153                                 throw new ArgumentOutOfRangeException ("value");
154                 }
155
156                 
157                 public Unit (string value) : this (value, '.')
158                 {
159                 }
160
161                 public Unit (string value, CultureInfo culture) : this (value, culture.NumberFormat.NumberDecimalSeparator [0])
162                 {
163                 }
164
165                 internal Unit (string value, CultureInfo culture, UnitType t) : this (value, '.')
166                 {
167                 }
168                 
169                 public bool IsEmpty {
170                         get {
171                                 return type == 0;
172                         }
173                 }
174
175                 public UnitType Type {
176                         get {
177                                 if (type == 0)
178                                         return UnitType.Pixel;
179                                 return type;
180                         }
181                 }
182
183                 public double Value {
184                         get {
185                                 return value;
186                         }
187                 }
188                 
189                 public static Unit Parse (string s)
190                 {
191                         return new Unit (s);
192                 }
193
194                 public static System.Web.UI.WebControls.Unit Parse (string s, System.Globalization.CultureInfo culture)
195                 {
196                         return new Unit (s, culture);
197                 }
198                 
199
200                 public static Unit Percentage (double n)
201                 {
202                         return new Unit (n, UnitType.Percentage);
203                 }
204                 
205                 public static Unit Pixel (int n)
206                 {
207                         return new Unit (n);
208                 }
209                 
210                 public static Unit Point (int n)
211                 {
212                         return new Unit (n, UnitType.Point);
213                 }
214                                 
215                 public override bool Equals (object obj)
216                 {
217                         if (obj is Unit){
218                                 Unit other = (Unit) obj;
219                                 return (other.type == type && other.value == value);
220                         }
221                         return false;
222                 }
223                 
224                 public override int GetHashCode ()
225                 {
226                         return Type.GetHashCode () ^ Value.GetHashCode ();
227                 }
228                 
229                 public static bool operator == (Unit left, Unit right)
230                 {
231                         return left.Type == right.Type && left.Value == right.Value;
232                 }
233
234                 public static bool operator != (Unit left, Unit right)
235                 {
236                         return left.Type != right.Type || left.Value != right.Value;
237                 }
238                 
239                 public static implicit operator Unit (int n)
240                 {
241                         return new Unit (n);
242                 }
243
244                 string GetExtension ()
245                 {
246                         switch (type){
247                         case UnitType.Pixel: return "px";
248                         case UnitType.Point: return "pt";
249                         case UnitType.Pica: return "pc";
250                         case UnitType.Inch: return "in";
251                         case UnitType.Mm: return "mm";
252                         case UnitType.Cm: return "cm";
253                         case UnitType.Percentage: return "%";
254                         case UnitType.Em: return "em";
255                         case UnitType.Ex: return "ex";
256                         default: return "";
257                         }
258                 }
259
260                 public string ToString (CultureInfo culture)
261                 {
262                         if (type == 0)
263                                 return "";
264                         
265                         string ex = GetExtension ();
266                         
267                         return String.Format (culture, "{0}{1}", value, ex);
268                 }
269                         
270                 public override string ToString ()
271                 {
272                         return ToString (CultureInfo.InvariantCulture);
273                 }
274
275 #if NET_2_0
276                 public string ToString (IFormatProvider provider)
277                 {
278                         if (type == 0)
279                                 return "";
280
281                         string ex = GetExtension ();
282
283                         return String.Format (provider, "{0}{1}", value, ex);
284                 }
285 #endif
286         }
287
288 }