1 //------------------------------------------------------------------------------ 2 // <copyright file="Unit.cs" company="Microsoft"> 3 // Copyright (c) Microsoft Corporation. All rights reserved. 4 // </copyright> 5 //------------------------------------------------------------------------------ 6 7 namespace System.Web.UI.WebControls { 8 9 using System; 10 using System.Globalization; 11 using System.ComponentModel; 12 using System.ComponentModel.Design; 13 using System.Security.Permissions; 14 using System.Web.Util; 15 16 [ 17 TypeConverterAttribute(typeof(UnitConverter)) 18 ] 19 [Serializable] 20 public struct Unit { 21 22 23 /// <devdoc> 24 /// Specifies an empty unit. 25 /// </devdoc> 26 public static readonly Unit Empty = new Unit(); 27 28 internal const int MaxValue = 32767; 29 internal const int MinValue = -32768; 30 31 private readonly UnitType type; 32 private readonly double value; 33 34 35 /// <devdoc> 36 /// <para>Initializes a new instance of the <see cref='System.Web.UI.WebControls.Unit'/> structure with the specified 32-bit signed integer as 37 /// the unit value and <see langword='Pixel'/> as the (default) unit type.</para> 38 /// </devdoc> UnitSystem.Web.UI.WebControls.Unit39 public Unit(int value) { 40 if ((value < MinValue) || (value > MaxValue)) { 41 throw new ArgumentOutOfRangeException("value"); 42 } 43 44 this.value = value; 45 this.type = UnitType.Pixel; 46 } 47 48 49 /// <devdoc> 50 /// <para> Initializes a new instance of the <see cref='System.Web.UI.WebControls.Unit'/> structure with the 51 /// specified double-precision 52 /// floating point number as the unit value and <see langword='Pixel'/> 53 /// as the (default) unit type.</para> 54 /// </devdoc> UnitSystem.Web.UI.WebControls.Unit55 public Unit(double value) { 56 if ((value < MinValue) || (value > MaxValue)) { 57 throw new ArgumentOutOfRangeException("value"); 58 } 59 this.value = (int)value; 60 this.type = UnitType.Pixel; 61 } 62 63 64 /// <devdoc> 65 /// <para>Initializes a new instance of the <see cref='System.Web.UI.WebControls.Unit'/> structure with the specified 66 /// double-precision floating point number as the unit value and the specified 67 /// <see cref='System.Web.UI.WebControls.UnitType'/> as the unit type.</para> 68 /// </devdoc> UnitSystem.Web.UI.WebControls.Unit69 public Unit(double value, UnitType type) { 70 if ((value < MinValue) || (value > MaxValue)) { 71 throw new ArgumentOutOfRangeException("value"); 72 } 73 if (type == UnitType.Pixel) { 74 this.value = (int)value; 75 } 76 else { 77 this.value = value; 78 } 79 this.type = type; 80 } 81 82 83 /// <devdoc> 84 /// <para>Initializes a new instance of the <see cref='System.Web.UI.WebControls.Unit'/> structure with the specified text 85 /// string that contains the unit value and unit type. If the unit type is not 86 /// specified, the default is <see langword='Pixel'/> 87 /// . </para> 88 /// </devdoc> UnitSystem.Web.UI.WebControls.Unit89 public Unit(string value) : this(value, CultureInfo.CurrentCulture, UnitType.Pixel) { 90 } 91 92 93 /// <devdoc> 94 /// <para>[To be supplied.]</para> 95 /// </devdoc> UnitSystem.Web.UI.WebControls.Unit96 public Unit(string value, CultureInfo culture) : this(value, culture, UnitType.Pixel) { 97 } 98 UnitSystem.Web.UI.WebControls.Unit99 internal Unit(string value, CultureInfo culture, UnitType defaultType) { 100 if (String.IsNullOrEmpty(value)) { 101 this.value = 0; 102 this.type = (UnitType)0; 103 } 104 else { 105 if (culture == null) { 106 culture = CultureInfo.CurrentCulture; 107 } 108 109 // This is invariant because it acts like an enum with a number together. 110 // The enum part is invariant, but the number uses current culture. 111 string trimLcase = value.Trim().ToLower(CultureInfo.InvariantCulture); 112 int len = trimLcase.Length; 113 114 int lastDigit = -1; 115 for (int i = 0; i < len; i++) { 116 char ch = trimLcase[i]; 117 if (((ch < '0') || (ch > '9')) && (ch != '-') && (ch != '.') && (ch != ',')) 118 break; 119 lastDigit = i; 120 } 121 if (lastDigit == -1) { 122 throw new FormatException(SR.GetString(SR.UnitParseNoDigits, value)); 123 } 124 if (lastDigit < len - 1) { 125 type = (UnitType)GetTypeFromString(trimLcase.Substring(lastDigit+1).Trim()); 126 } 127 else { 128 type = defaultType; 129 } 130 131 string numericPart = trimLcase.Substring(0, lastDigit+1); 132 // Cannot use Double.FromString, because we don't use it in the ToString implementation 133 try { 134 TypeConverter converter = new SingleConverter(); 135 this.value = (Single)converter.ConvertFromString(null, culture, numericPart); 136 137 if (type == UnitType.Pixel) { 138 this.value = (int)this.value; 139 } 140 } 141 catch { 142 throw new FormatException(SR.GetString(SR.UnitParseNumericPart, value, numericPart, type.ToString("G"))); 143 } 144 if ((this.value < MinValue) || (this.value > MaxValue)) { 145 throw new ArgumentOutOfRangeException("value"); 146 } 147 } 148 } 149 150 151 /// <devdoc> 152 /// <para>Gets a value indicating whether the <see cref='System.Web.UI.WebControls.Unit'/> is empty.</para> 153 /// </devdoc> 154 public bool IsEmpty { 155 get { 156 return type == (UnitType)0; 157 } 158 } 159 160 161 /// <devdoc> 162 /// <para>Gets or sets the type of the <see cref='System.Web.UI.WebControls.Unit'/> .</para> 163 /// </devdoc> 164 public UnitType Type { 165 get { 166 if (!IsEmpty) { 167 return this.type; 168 } 169 else { 170 return UnitType.Pixel; 171 } 172 } 173 } 174 175 176 /// <devdoc> 177 /// <para>Gets the value of the <see cref='System.Web.UI.WebControls.Unit'/> .</para> 178 /// </devdoc> 179 public double Value { 180 get { 181 return this.value; 182 } 183 } 184 185 186 /// <devdoc> 187 /// <para>[To be supplied.]</para> 188 /// </devdoc> GetHashCodeSystem.Web.UI.WebControls.Unit189 public override int GetHashCode() { 190 return HashCodeCombiner.CombineHashCodes(type.GetHashCode(), value.GetHashCode()); 191 } 192 193 194 /// <devdoc> 195 /// <para>Compares this <see cref='System.Web.UI.WebControls.Unit'/> with the specified object.</para> 196 /// </devdoc> EqualsSystem.Web.UI.WebControls.Unit197 public override bool Equals(object obj) { 198 if (obj == null || !(obj is Unit)) { 199 return false; 200 } 201 Unit u = (Unit)obj; 202 203 // compare internal values to avoid "defaulting" in the case of "Empty" 204 // 205 if (u.type == type && u.value == value) { 206 return true; 207 } 208 209 return false; 210 } 211 212 213 /// <devdoc> 214 /// <para>Compares two units to find out if they have the same value and type.</para> 215 /// </devdoc> operator ==System.Web.UI.WebControls.Unit216 public static bool operator ==(Unit left, Unit right) { 217 218 // compare internal values to avoid "defaulting" in the case of "Empty" 219 // 220 return (left.type == right.type && left.value == right.value); 221 } 222 223 224 /// <devdoc> 225 /// <para>Compares two units to find out if they have different 226 /// values and/or types.</para> 227 /// </devdoc> operator !=System.Web.UI.WebControls.Unit228 public static bool operator !=(Unit left, Unit right) { 229 230 // compare internal values to avoid "defaulting" in the case of "Empty" 231 // 232 return (left.type != right.type || left.value != right.value); 233 } 234 235 236 237 /// <devdoc> 238 /// Converts UnitType to persistence string. 239 /// </devdoc> GetStringFromTypeSystem.Web.UI.WebControls.Unit240 private static string GetStringFromType(UnitType type) { 241 switch (type) { 242 case UnitType.Pixel: 243 return "px"; 244 case UnitType.Point: 245 return "pt"; 246 case UnitType.Pica: 247 return "pc"; 248 case UnitType.Inch: 249 return "in"; 250 case UnitType.Mm: 251 return "mm"; 252 case UnitType.Cm: 253 return "cm"; 254 case UnitType.Percentage: 255 return "%"; 256 case UnitType.Em: 257 return "em"; 258 case UnitType.Ex: 259 return "ex"; 260 } 261 return String.Empty; 262 } 263 264 265 /// <devdoc> 266 /// Converts persistence string to UnitType. 267 /// </devdoc> GetTypeFromStringSystem.Web.UI.WebControls.Unit268 private static UnitType GetTypeFromString(string value) { 269 if (!String.IsNullOrEmpty(value)) { 270 if (value.Equals("px")) { 271 return UnitType.Pixel; 272 } 273 else if (value.Equals("pt")) { 274 return UnitType.Point; 275 } 276 else if (value.Equals("%")) { 277 return UnitType.Percentage; 278 } 279 else if (value.Equals("pc")) { 280 return UnitType.Pica; 281 } 282 else if (value.Equals("in")) { 283 return UnitType.Inch; 284 } 285 else if (value.Equals("mm")) { 286 return UnitType.Mm; 287 } 288 else if (value.Equals("cm")) { 289 return UnitType.Cm; 290 } 291 else if (value.Equals("em")) { 292 return UnitType.Em; 293 } 294 else if (value.Equals("ex")) { 295 return UnitType.Ex; 296 } 297 else { 298 throw new ArgumentOutOfRangeException("value"); 299 } 300 } 301 return UnitType.Pixel; 302 } 303 304 305 /// <devdoc> 306 /// <para>[To be supplied.]</para> 307 /// </devdoc> ParseSystem.Web.UI.WebControls.Unit308 public static Unit Parse(string s) { 309 return new Unit(s, CultureInfo.CurrentCulture); 310 } 311 312 313 /// <devdoc> 314 /// <para>[To be supplied.]</para> 315 /// </devdoc> ParseSystem.Web.UI.WebControls.Unit316 public static Unit Parse(string s, CultureInfo culture) { 317 return new Unit(s, culture); 318 } 319 320 321 /// <devdoc> 322 /// <para>Creates a <see cref='System.Web.UI.WebControls.Unit'/> of type <see langword='Percentage'/> from the specified 32-bit signed integer.</para> 323 /// </devdoc> PercentageSystem.Web.UI.WebControls.Unit324 public static Unit Percentage(double n) { 325 return new Unit(n,UnitType.Percentage); 326 } 327 328 329 /// <devdoc> 330 /// <para>Creates a <see cref='System.Web.UI.WebControls.Unit'/> of type <see langword='Pixel'/> from the specified 32-bit signed integer.</para> 331 /// </devdoc> PixelSystem.Web.UI.WebControls.Unit332 public static Unit Pixel(int n) { 333 return new Unit(n); 334 } 335 336 337 /// <devdoc> 338 /// <para>Creates a <see cref='System.Web.UI.WebControls.Unit'/> of type <see langword='Point'/> from the 339 /// specified 32-bit signed integer.</para> 340 /// </devdoc> PointSystem.Web.UI.WebControls.Unit341 public static Unit Point(int n) { 342 return new Unit(n,UnitType.Point); 343 } 344 345 346 /// <internalonly/> 347 /// <devdoc> 348 /// <para>Converts a <see cref='System.Web.UI.WebControls.Unit'/> to a <see cref='System.String' qualify='true'/> .</para> 349 /// </devdoc> ToStringSystem.Web.UI.WebControls.Unit350 public override string ToString() { 351 return ToString((IFormatProvider)CultureInfo.CurrentCulture); 352 } 353 354 ToStringSystem.Web.UI.WebControls.Unit355 public string ToString(CultureInfo culture) { 356 return ToString((IFormatProvider)culture); 357 } 358 359 ToStringSystem.Web.UI.WebControls.Unit360 public string ToString(IFormatProvider formatProvider) { 361 if (IsEmpty) 362 return String.Empty; 363 364 // Double.ToString does not do the right thing, we get extra bits at the end 365 string valuePart; 366 if (type == UnitType.Pixel) { 367 valuePart = ((int)value).ToString(formatProvider); 368 } 369 else { 370 valuePart = ((float)value).ToString(formatProvider); 371 } 372 373 return valuePart + Unit.GetStringFromType(type); 374 } 375 376 377 /// <devdoc> 378 /// <para>Implicitly creates a <see cref='System.Web.UI.WebControls.Unit'/> of type <see langword='Pixel'/> from the specified 32-bit unsigned integer.</para> 379 /// </devdoc> operator UnitSystem.Web.UI.WebControls.Unit380 public static implicit operator Unit(int n) { 381 return Unit.Pixel(n); 382 } 383 } 384 } 385