1 // 2 // VisualStyleRenderer.cs 3 // 4 // Permission is hereby granted, free of charge, to any person obtaining 5 // a copy of this software and associated documentation files (the 6 // "Software"), to deal in the Software without restriction, including 7 // without limitation the rights to use, copy, modify, merge, publish, 8 // distribute, sublicense, and/or sell copies of the Software, and to 9 // permit persons to whom the Software is furnished to do so, subject to 10 // the following conditions: 11 // 12 // The above copyright notice and this permission notice shall be 13 // included in all copies or substantial portions of the Software. 14 // 15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 // 23 // Copyright (c) 2006 Novell, Inc. 24 // 25 // Authors: 26 // Jonathan Pobst (monkey@jpobst.com) 27 // 28 29 using System.Drawing; 30 31 namespace System.Windows.Forms.VisualStyles 32 { 33 public sealed class VisualStyleRenderer 34 { 35 private string class_name; 36 private int part; 37 private int state; 38 private IntPtr theme; 39 private int last_hresult = 0; 40 private ThemeHandleManager theme_handle_manager = new ThemeHandleManager (); 41 42 #region Public Constructors VisualStyleRenderer(string className, int part, int state)43 public VisualStyleRenderer (string className, int part, int state) 44 { 45 theme_handle_manager.VisualStyleRenderer = this; 46 this.SetParameters (className, part, state); 47 } 48 VisualStyleRenderer(VisualStyleElement element)49 public VisualStyleRenderer (VisualStyleElement element) 50 : this (element.ClassName, element.Part, element.State) { 51 } 52 #endregion 53 54 #region Public Properties 55 public String Class { get { return this.class_name; } } 56 public IntPtr Handle { get { return this.theme; } } 57 public int LastHResult { get { return this.last_hresult; } } 58 public int Part { get { return this.part; } } 59 public int State { get { return this.state; } } 60 61 public static bool IsSupported { 62 get { 63 if (!VisualStyleInformation.IsEnabledByUser) 64 return false; 65 66 if (Application.VisualStyleState == VisualStyleState.ClientAndNonClientAreasEnabled || 67 Application.VisualStyleState == VisualStyleState.ClientAreaEnabled) 68 return true; 69 70 return false; 71 } 72 } 73 #endregion 74 75 #region Public Static Methods IsElementDefined(VisualStyleElement element)76 public static bool IsElementDefined (VisualStyleElement element) 77 { 78 if (!IsSupported) 79 throw new InvalidOperationException ("Visual Styles are not enabled."); 80 81 if (IsElementKnownToBeSupported (element.ClassName, element.Part, element.State)) 82 return true; 83 84 IntPtr theme = VisualStyles.UxThemeOpenThemeData (IntPtr.Zero, element.ClassName); 85 if (theme == IntPtr.Zero) 86 return false; 87 bool retval = VisualStyles.UxThemeIsThemePartDefined (theme, element.Part); 88 VisualStyles.UxThemeCloseThemeData (theme); 89 90 return retval; 91 } 92 #endregion 93 94 #region Public Instance Methods DrawBackground(IDeviceContext dc, Rectangle bounds)95 public void DrawBackground (IDeviceContext dc, Rectangle bounds) 96 { 97 if (dc == null) 98 throw new ArgumentNullException ("dc"); 99 100 last_hresult = VisualStyles.UxThemeDrawThemeBackground (theme, dc, this.part, this.state, bounds); 101 } 102 DrawBackground(IDeviceContext dc, Rectangle bounds, Rectangle clipRectangle)103 public void DrawBackground (IDeviceContext dc, Rectangle bounds, Rectangle clipRectangle) 104 { 105 if (dc == null) 106 throw new ArgumentNullException ("dc"); 107 108 last_hresult = VisualStyles.UxThemeDrawThemeBackground (theme, dc, this.part, this.state, bounds, clipRectangle); 109 } 110 DrawEdge(IDeviceContext dc, Rectangle bounds, Edges edges, EdgeStyle style, EdgeEffects effects)111 public Rectangle DrawEdge (IDeviceContext dc, Rectangle bounds, Edges edges, EdgeStyle style, EdgeEffects effects) 112 { 113 if (dc == null) 114 throw new ArgumentNullException ("dc"); 115 116 Rectangle result; 117 last_hresult = VisualStyles.UxThemeDrawThemeEdge (theme, dc, this.part, this.state, bounds, edges, style, effects, out result); 118 return result; 119 } 120 DrawImage(Graphics g, Rectangle bounds, ImageList imageList, int imageIndex)121 public void DrawImage (Graphics g, Rectangle bounds, ImageList imageList, int imageIndex) 122 { 123 if (g == null) 124 throw new ArgumentNullException ("g"); 125 if (imageIndex < 0 || imageIndex > imageList.Images.Count - 1) 126 throw new ArgumentOutOfRangeException ("imageIndex"); 127 if (imageList.Images[imageIndex] == null) 128 throw new ArgumentNullException ("imageIndex"); 129 130 g.DrawImage (imageList.Images[imageIndex], bounds); 131 } 132 DrawImage(Graphics g, Rectangle bounds, Image image)133 public void DrawImage (Graphics g, Rectangle bounds, Image image) 134 { 135 if (g == null) 136 throw new ArgumentNullException ("g"); 137 if (image == null) 138 throw new ArgumentNullException ("image"); 139 140 g.DrawImage (image, bounds); 141 } 142 DrawParentBackground(IDeviceContext dc, Rectangle bounds, Control childControl)143 public void DrawParentBackground (IDeviceContext dc, Rectangle bounds, Control childControl) 144 { 145 if (dc == null) 146 throw new ArgumentNullException ("dc"); 147 148 last_hresult = VisualStyles.UxThemeDrawThemeParentBackground (dc, bounds, childControl); 149 } 150 DrawText(IDeviceContext dc, Rectangle bounds, string textToDraw, bool drawDisabled, TextFormatFlags flags)151 public void DrawText (IDeviceContext dc, Rectangle bounds, string textToDraw, bool drawDisabled, TextFormatFlags flags) 152 { 153 if (dc == null) 154 throw new ArgumentNullException ("dc"); 155 156 last_hresult = VisualStyles.UxThemeDrawThemeText (theme, dc, this.part, this.state, textToDraw, flags, bounds); 157 } 158 DrawText(IDeviceContext dc, Rectangle bounds, string textToDraw, bool drawDisabled)159 public void DrawText (IDeviceContext dc, Rectangle bounds, string textToDraw, bool drawDisabled) 160 { 161 this.DrawText (dc, bounds, textToDraw, drawDisabled, TextFormatFlags.Default); 162 } 163 DrawText(IDeviceContext dc, Rectangle bounds, string textToDraw)164 public void DrawText (IDeviceContext dc, Rectangle bounds, string textToDraw) 165 { 166 this.DrawText (dc, bounds, textToDraw, false, TextFormatFlags.Default); 167 } 168 GetBackgroundContentRectangle(IDeviceContext dc, Rectangle bounds)169 public Rectangle GetBackgroundContentRectangle (IDeviceContext dc, Rectangle bounds) 170 { 171 if (dc == null) 172 throw new ArgumentNullException ("dc"); 173 174 Rectangle result; 175 last_hresult = VisualStyles.UxThemeGetThemeBackgroundContentRect (theme, dc, this.part, this.state, bounds, out result); 176 return result; 177 } 178 GetBackgroundExtent(IDeviceContext dc, Rectangle contentBounds)179 public Rectangle GetBackgroundExtent (IDeviceContext dc, Rectangle contentBounds) 180 { 181 if (dc == null) 182 throw new ArgumentNullException ("dc"); 183 184 Rectangle result; 185 last_hresult = VisualStyles.UxThemeGetThemeBackgroundExtent (theme, dc, this.part, this.state, contentBounds, out result); 186 return result; 187 } 188 189 [System.Security.SuppressUnmanagedCodeSecurity] GetBackgroundRegion(IDeviceContext dc, Rectangle bounds)190 public Region GetBackgroundRegion (IDeviceContext dc, Rectangle bounds) 191 { 192 if (dc == null) 193 throw new ArgumentNullException ("dc"); 194 195 Region result; 196 last_hresult = VisualStyles.UxThemeGetThemeBackgroundRegion (theme, dc, this.part, this.state, bounds, out result); 197 return result; 198 } 199 GetBoolean(BooleanProperty prop)200 public bool GetBoolean (BooleanProperty prop) 201 { 202 if (!Enum.IsDefined (typeof (BooleanProperty), prop)) 203 throw new System.ComponentModel.InvalidEnumArgumentException ("prop", (int)prop, typeof (BooleanProperty)); 204 205 bool result; 206 last_hresult = VisualStyles.UxThemeGetThemeBool (theme, this.part, this.state, prop, out result); 207 return result; 208 } 209 GetColor(ColorProperty prop)210 public Color GetColor (ColorProperty prop) 211 { 212 if (!Enum.IsDefined (typeof (ColorProperty), prop)) 213 throw new System.ComponentModel.InvalidEnumArgumentException ("prop", (int)prop, typeof (ColorProperty)); 214 215 Color result; 216 last_hresult = VisualStyles.UxThemeGetThemeColor (theme, this.part, this.state, prop, out result); 217 return result; 218 } 219 GetEnumValue(EnumProperty prop)220 public int GetEnumValue (EnumProperty prop) 221 { 222 if (!Enum.IsDefined (typeof (EnumProperty), prop)) 223 throw new System.ComponentModel.InvalidEnumArgumentException ("prop", (int)prop, typeof (EnumProperty)); 224 225 int result; 226 last_hresult = VisualStyles.UxThemeGetThemeEnumValue (theme, this.part, this.state, prop, out result); 227 return result; 228 } 229 GetFilename(FilenameProperty prop)230 public string GetFilename (FilenameProperty prop) 231 { 232 if (!Enum.IsDefined (typeof (FilenameProperty), prop)) 233 throw new System.ComponentModel.InvalidEnumArgumentException ("prop", (int)prop, typeof (FilenameProperty)); 234 235 string result; 236 last_hresult = VisualStyles.UxThemeGetThemeFilename (theme, this.part, this.state, prop, out result); 237 return result; 238 239 } 240 241 [MonoTODO(@"I can't get MS's to return anything but null, so I can't really get this one right")] GetFont(IDeviceContext dc, FontProperty prop)242 public Font GetFont (IDeviceContext dc, FontProperty prop) 243 { 244 throw new NotImplementedException(); 245 //if (dc == null) 246 // throw new ArgumentNullException ("dc"); 247 //if (!Enum.IsDefined (typeof (FontProperty), prop)) 248 // throw new System.ComponentModel.InvalidEnumArgumentException ("prop", (int)prop, typeof (FontProperty)); 249 250 //UXTheme.LOGFONT lf = new UXTheme.LOGFONT(); 251 252 //UXTheme.GetThemeFont (theme, dc.GetHdc (), this.part, this.state, (int)prop, out lf); 253 //IntPtr fontPtr = UXTheme.CreateFontIndirect(lf); 254 //dc.ReleaseHdc(); 255 256 //return Font.FromLogFont(lf); 257 //return null; 258 } 259 GetInteger(IntegerProperty prop)260 public int GetInteger (IntegerProperty prop) 261 { 262 if (!Enum.IsDefined (typeof (IntegerProperty), prop)) 263 throw new System.ComponentModel.InvalidEnumArgumentException ("prop", (int)prop, typeof (IntegerProperty)); 264 265 int result; 266 last_hresult = VisualStyles.UxThemeGetThemeInt (theme, this.part, this.state, prop, out result); 267 return result; 268 } 269 270 [MonoTODO(@"MS's causes a PInvokeStackUnbalance on me, so this is not verified against MS.")] GetMargins(IDeviceContext dc, MarginProperty prop)271 public Padding GetMargins (IDeviceContext dc, MarginProperty prop) 272 { 273 if (dc == null) 274 throw new ArgumentNullException ("dc"); 275 if (!Enum.IsDefined (typeof (MarginProperty), prop)) 276 throw new System.ComponentModel.InvalidEnumArgumentException ("prop", (int)prop, typeof (MarginProperty)); 277 278 Padding result; 279 last_hresult = VisualStyles.UxThemeGetThemeMargins (theme, dc, this.part, this.state, prop, out result); 280 return result; 281 } 282 GetPartSize(IDeviceContext dc, Rectangle bounds, ThemeSizeType type)283 public Size GetPartSize (IDeviceContext dc, Rectangle bounds, ThemeSizeType type) 284 { 285 if (dc == null) 286 throw new ArgumentNullException ("dc"); 287 if (!Enum.IsDefined (typeof (ThemeSizeType), type)) 288 throw new System.ComponentModel.InvalidEnumArgumentException ("prop", (int)type, typeof (ThemeSizeType)); 289 290 Size result; 291 last_hresult = VisualStyles.UxThemeGetThemePartSize (theme, dc, this.part, this.state, bounds, type, out result); 292 return result; 293 } 294 GetPartSize(IDeviceContext dc, ThemeSizeType type)295 public Size GetPartSize (IDeviceContext dc, ThemeSizeType type) 296 { 297 if (dc == null) 298 throw new ArgumentNullException ("dc"); 299 if (!Enum.IsDefined (typeof (ThemeSizeType), type)) 300 throw new System.ComponentModel.InvalidEnumArgumentException ("prop", (int)type, typeof (ThemeSizeType)); 301 302 Size result; 303 last_hresult = VisualStyles.UxThemeGetThemePartSize (theme, dc, this.part, this.state, type, out result); 304 return result; 305 } 306 GetPoint(PointProperty prop)307 public Point GetPoint (PointProperty prop) 308 { 309 if (!Enum.IsDefined (typeof (PointProperty), prop)) 310 throw new System.ComponentModel.InvalidEnumArgumentException ("prop", (int)prop, typeof (PointProperty)); 311 312 Point result; 313 last_hresult = VisualStyles.UxThemeGetThemePosition (theme, this.part, this.state, prop, out result); 314 return result; 315 } 316 317 [MonoTODO(@"Can't find any values that return anything on MS to test against")] GetString(StringProperty prop)318 public string GetString (StringProperty prop) 319 { 320 if (!Enum.IsDefined (typeof (StringProperty), prop)) 321 throw new System.ComponentModel.InvalidEnumArgumentException ("prop", (int)prop, typeof (StringProperty)); 322 323 string result; 324 last_hresult = VisualStyles.UxThemeGetThemeString (theme, this.part, this.state, prop, out result); 325 return result; 326 } 327 GetTextExtent(IDeviceContext dc, Rectangle bounds, string textToDraw, TextFormatFlags flags)328 public Rectangle GetTextExtent (IDeviceContext dc, Rectangle bounds, string textToDraw, TextFormatFlags flags) 329 { 330 if (dc == null) 331 throw new ArgumentNullException ("dc"); 332 333 Rectangle result; 334 last_hresult = VisualStyles.UxThemeGetThemeTextExtent (theme, dc, this.part, this.state, textToDraw, flags, bounds, out result); 335 return result; 336 } 337 GetTextExtent(IDeviceContext dc, string textToDraw, TextFormatFlags flags)338 public Rectangle GetTextExtent (IDeviceContext dc, string textToDraw, TextFormatFlags flags) 339 { 340 if (dc == null) 341 throw new ArgumentNullException ("dc"); 342 343 Rectangle result; 344 last_hresult = VisualStyles.UxThemeGetThemeTextExtent (theme, dc, this.part, this.state, textToDraw, flags, out result); 345 return result; 346 } 347 GetTextMetrics(IDeviceContext dc)348 public TextMetrics GetTextMetrics (IDeviceContext dc) 349 { 350 if (dc == null) 351 throw new ArgumentNullException ("dc", "dc cannot be null."); 352 353 TextMetrics result; 354 last_hresult = VisualStyles.UxThemeGetThemeTextMetrics (theme, dc, this.part, this.state, out result); 355 return result; 356 } 357 HitTestBackground(IDeviceContext dc, Rectangle backgroundRectangle, IntPtr hRgn, Point pt, HitTestOptions options)358 public HitTestCode HitTestBackground (IDeviceContext dc, Rectangle backgroundRectangle, IntPtr hRgn, Point pt, HitTestOptions options) 359 { 360 if (dc == null) 361 throw new ArgumentNullException ("dc"); 362 363 HitTestCode result; 364 last_hresult = VisualStyles.UxThemeHitTestThemeBackground(theme, dc, this.part, this.state, options, backgroundRectangle, hRgn, pt, out result); 365 return result; 366 } 367 HitTestBackground(Graphics g, Rectangle backgroundRectangle, Region region, Point pt, HitTestOptions options)368 public HitTestCode HitTestBackground (Graphics g, Rectangle backgroundRectangle, Region region, Point pt, HitTestOptions options) 369 { 370 if (g == null) 371 throw new ArgumentNullException ("g"); 372 373 IntPtr hRgn = region.GetHrgn(g); 374 375 return this.HitTestBackground(g, backgroundRectangle, hRgn, pt, options); 376 } 377 HitTestBackground(IDeviceContext dc, Rectangle backgroundRectangle, Point pt, HitTestOptions options)378 public HitTestCode HitTestBackground (IDeviceContext dc, Rectangle backgroundRectangle, Point pt, HitTestOptions options) 379 { 380 return this.HitTestBackground (dc, backgroundRectangle, IntPtr.Zero, pt, options); 381 } 382 IsBackgroundPartiallyTransparent()383 public bool IsBackgroundPartiallyTransparent () 384 { 385 return VisualStyles.UxThemeIsThemeBackgroundPartiallyTransparent (theme, this.part, this.state); 386 } 387 SetParameters(string className, int part, int state)388 public void SetParameters (string className, int part, int state) 389 { 390 if (theme != IntPtr.Zero) 391 last_hresult = VisualStyles.UxThemeCloseThemeData (theme); 392 393 if (!IsSupported) 394 throw new InvalidOperationException ("Visual Styles are not enabled."); 395 396 this.class_name = className; 397 this.part = part; 398 this.state = state; 399 theme = VisualStyles.UxThemeOpenThemeData (IntPtr.Zero, this.class_name); 400 401 if (IsElementKnownToBeSupported (className, part, state)) 402 return; 403 if (theme == IntPtr.Zero || !VisualStyles.UxThemeIsThemePartDefined (theme, this.part)) 404 throw new ArgumentException ("This element is not supported by the current visual style."); 405 } 406 SetParameters(VisualStyleElement element)407 public void SetParameters (VisualStyleElement element) 408 { 409 this.SetParameters (element.ClassName, element.Part, element.State); 410 } 411 #endregion 412 413 #region Private Properties 414 internal static IVisualStyles VisualStyles { 415 get { return VisualStylesEngine.Instance; } 416 } 417 #endregion 418 419 #region Private Instance Methods DrawBackgroundExcludingArea(IDeviceContext dc, Rectangle bounds, Rectangle excludedArea)420 internal void DrawBackgroundExcludingArea (IDeviceContext dc, Rectangle bounds, Rectangle excludedArea) 421 { 422 VisualStyles.VisualStyleRendererDrawBackgroundExcludingArea (theme, dc, part, state, bounds, excludedArea); 423 } 424 #endregion 425 426 #region Private Static Methods IsElementKnownToBeSupported(string className, int part, int state)427 private static bool IsElementKnownToBeSupported (string className, int part, int state) 428 { 429 return className == "STATUS" && part == 0 && state == 0; 430 } 431 #endregion 432 433 #region Private Classes 434 private class ThemeHandleManager 435 { 436 public VisualStyleRenderer VisualStyleRenderer; ~ThemeHandleManager()437 ~ThemeHandleManager () 438 { 439 if (VisualStyleRenderer.theme == IntPtr.Zero) 440 return; 441 VisualStyles.UxThemeCloseThemeData (VisualStyleRenderer.theme); 442 } 443 } 444 #endregion 445 } 446 } 447