2 // VisualStyleRenderer.cs
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:
12 // The above copyright notice and this permission notice shall be
13 // included in all copies or substantial portions of the Software.
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.
23 // Copyright (c) 2006 Novell, Inc.
26 // Jonathan Pobst (monkey@jpobst.com)
32 namespace System.Windows.Forms.VisualStyles
34 public sealed class VisualStyleRenderer
36 private string class_name;
40 private int last_hresult = 0;
42 #region Public Constructors
43 public VisualStyleRenderer (string className, int part, int state)
45 this.SetParameters (className, part, state);
48 public VisualStyleRenderer (VisualStyleElement element)
50 this.SetParameters (element);
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; } }
61 public static bool IsSupported {
63 if (!VisualStyleInformation.IsEnabledByUser)
66 if (Application.VisualStyleState == VisualStyleState.ClientAndNonClientAreasEnabled ||
67 Application.VisualStyleState == VisualStyleState.ClientAreaEnabled)
75 #region Public Static Methods
76 public static bool IsElementDefined (VisualStyleElement element)
79 throw new InvalidOperationException ("Visual Styles are not enabled.");
81 IntPtr theme = UXTheme.OpenThemeData (IntPtr.Zero, element.ClassName);
82 bool retval = UXTheme.IsThemePartDefined (theme, element.Part, 0);
83 UXTheme.CloseThemeData (theme);
89 #region Public Instance Methods
90 public void DrawBackground (IDeviceContext dc, Rectangle bounds)
93 throw new ArgumentNullException ("dc");
95 XplatUIWin32.RECT BoundsRect = XplatUIWin32.RECT.FromRectangle (bounds);
97 last_hresult = UXTheme.DrawThemeBackground (theme, dc.GetHdc (), this.part, this.state, ref BoundsRect, IntPtr.Zero);
101 public void DrawBackground (IDeviceContext dc, Rectangle bounds, Rectangle clipRectangle)
104 throw new ArgumentNullException ("dc");
106 XplatUIWin32.RECT BoundsRect = XplatUIWin32.RECT.FromRectangle (bounds);
107 XplatUIWin32.RECT ClipRect = XplatUIWin32.RECT.FromRectangle (clipRectangle);
109 last_hresult = UXTheme.DrawThemeBackground (theme, dc.GetHdc (), this.part, this.state, ref BoundsRect, ref ClipRect);
113 public Rectangle DrawEdge (IDeviceContext dc, Rectangle bounds, Edges edges, EdgeStyle style, EdgeEffects effects)
116 throw new ArgumentNullException ("dc");
118 XplatUIWin32.RECT BoundsRect = XplatUIWin32.RECT.FromRectangle (bounds);
119 XplatUIWin32.RECT retval;
121 last_hresult = UXTheme.DrawThemeEdge (theme, dc.GetHdc (), this.part, this.state, ref BoundsRect, (uint)style, (uint)edges + (uint)effects, out retval);
123 return retval.ToRectangle ();
126 public void DrawImage (Graphics g, Rectangle bounds, ImageList imageList, int imageIndex)
129 throw new ArgumentNullException ("g");
130 if (imageIndex < 0 || imageIndex > imageList.Images.Count - 1)
131 throw new ArgumentOutOfRangeException ("imageIndex");
132 if (imageList.Images[imageIndex] == null)
133 throw new ArgumentNullException ("imageIndex");
135 g.DrawImage (imageList.Images[imageIndex], bounds);
138 public void DrawImage (Graphics g, Rectangle bounds, Image image)
141 throw new ArgumentNullException ("g");
143 throw new ArgumentNullException ("image");
145 g.DrawImage (image, bounds);
148 public void DrawParentBackground (IDeviceContext dc, Rectangle bounds, Control childControl)
151 throw new ArgumentNullException ("dc");
153 XplatUIWin32.RECT BoundsRect = XplatUIWin32.RECT.FromRectangle (bounds);
155 using (Graphics g = Graphics.FromHwnd (childControl.Handle)) {
156 last_hresult = UXTheme.DrawThemeParentBackground (childControl.Handle, g.GetHdc (), ref BoundsRect);
161 public void DrawText (IDeviceContext dc, Rectangle bounds, string textToDraw, bool drawDisabled, TextFormatFlags flags)
164 throw new ArgumentNullException ("dc");
166 XplatUIWin32.RECT BoundsRect = XplatUIWin32.RECT.FromRectangle (bounds);
168 last_hresult = UXTheme.DrawThemeText (theme, dc.GetHdc (), this.part, this.state, textToDraw, textToDraw.Length, (uint)flags, 0, ref BoundsRect);
172 public void DrawText (IDeviceContext dc, Rectangle bounds, string textToDraw, bool drawDisabled)
174 this.DrawText (dc, bounds, textToDraw, drawDisabled, TextFormatFlags.Default);
177 public void DrawText (IDeviceContext dc, Rectangle bounds, string textToDraw)
179 this.DrawText (dc, bounds, textToDraw, false, TextFormatFlags.Default);
182 public Rectangle GetBackgroundContentRectangle (IDeviceContext dc, Rectangle bounds)
185 throw new ArgumentNullException ("dc");
187 XplatUIWin32.RECT BoundsRect = XplatUIWin32.RECT.FromRectangle (bounds);
188 XplatUIWin32.RECT retval;
190 last_hresult = UXTheme.GetThemeBackgroundContentRect (theme, dc.GetHdc (), this.part, this.state, ref BoundsRect, out retval);
193 return retval.ToRectangle ();
196 public Rectangle GetBackgroundExtent (IDeviceContext dc, Rectangle contentBounds)
199 throw new ArgumentNullException ("dc");
201 XplatUIWin32.RECT BoundsRect = XplatUIWin32.RECT.FromRectangle (contentBounds);
202 XplatUIWin32.RECT retval = new XplatUIWin32.RECT ();
204 last_hresult = UXTheme.GetThemeBackgroundExtent (theme, dc.GetHdc (), this.part, this.state, ref BoundsRect, ref retval);
207 return retval.ToRectangle ();
210 [System.Security.SuppressUnmanagedCodeSecurity]
211 public Region GetBackgroundRegion (IDeviceContext dc, Rectangle bounds)
214 throw new ArgumentNullException ("dc");
216 XplatUIWin32.RECT BoundsRect = XplatUIWin32.RECT.FromRectangle (bounds);
219 last_hresult = UXTheme.GetThemeBackgroundRegion (theme, dc.GetHdc (), this.part, this.state, ref BoundsRect, out retval);
222 return Region.FromHrgn (retval);
225 public bool GetBoolean (BooleanProperty prop)
227 if (!Enum.IsDefined (typeof (BooleanProperty), prop))
228 throw new System.ComponentModel.InvalidEnumArgumentException ("prop", (int)prop, typeof (BooleanProperty));
231 last_hresult = UXTheme.GetThemeBool (theme, this.part, this.state, (int)prop, out retval);
233 return retval == 0 ? false : true;
236 public Color GetColor (ColorProperty prop)
238 if (!Enum.IsDefined (typeof (ColorProperty), prop))
239 throw new System.ComponentModel.InvalidEnumArgumentException ("prop", (int)prop, typeof (ColorProperty));
242 last_hresult = UXTheme.GetThemeColor (theme, this.part, this.state, (int)prop, out retval);
244 return System.Drawing.Color.FromArgb ((int)(0x000000FFU & retval),
245 (int)(0x0000FF00U & retval) >> 8, (int)(0x00FF0000U & retval) >> 16);
248 public int GetEnumValue (EnumProperty prop)
250 if (!Enum.IsDefined (typeof (EnumProperty), prop))
251 throw new System.ComponentModel.InvalidEnumArgumentException ("prop", (int)prop, typeof (EnumProperty));
254 last_hresult = UXTheme.GetThemeEnumValue (theme, this.part, this.state, (int)prop, out retval);
259 public string GetFilename (FilenameProperty prop)
261 if (!Enum.IsDefined (typeof (FilenameProperty), prop))
262 throw new System.ComponentModel.InvalidEnumArgumentException ("prop", (int)prop, typeof (FilenameProperty));
264 Text.StringBuilder sb = new Text.StringBuilder (255);
265 last_hresult = UXTheme.GetThemeFilename (theme, this.part, this.state, (int)prop, sb, sb.Capacity);
267 return sb.ToString ();
270 [MonoTODO(@"I can't get MS's to return anything but null, so I can't really get this one right")]
271 public Font GetFont (IDeviceContext dc, FontProperty prop)
273 throw new NotImplementedException();
275 // throw new ArgumentNullException ("dc");
276 //if (!Enum.IsDefined (typeof (FontProperty), prop))
277 // throw new System.ComponentModel.InvalidEnumArgumentException ("prop", (int)prop, typeof (FontProperty));
279 //UXTheme.LOGFONT lf = new UXTheme.LOGFONT();
281 //UXTheme.GetThemeFont (theme, dc.GetHdc (), this.part, this.state, (int)prop, out lf);
282 //IntPtr fontPtr = UXTheme.CreateFontIndirect(lf);
285 //return Font.FromLogFont(lf);
289 public int GetInteger (IntegerProperty prop)
291 if (!Enum.IsDefined (typeof (IntegerProperty), prop))
292 throw new System.ComponentModel.InvalidEnumArgumentException ("prop", (int)prop, typeof (IntegerProperty));
295 last_hresult = UXTheme.GetThemeInt (theme, this.part, this.state, (int)prop, out retval);
300 [MonoTODO(@"MS's causes a PInvokeStackUnbalance on me, so this is not verified against MS.")]
301 public Padding GetMargins (IDeviceContext dc, MarginProperty prop)
304 throw new ArgumentNullException ("dc");
305 if (!Enum.IsDefined (typeof (MarginProperty), prop))
306 throw new System.ComponentModel.InvalidEnumArgumentException ("prop", (int)prop, typeof (MarginProperty));
309 UXTheme.MARGINS retval = new UXTheme.MARGINS ();
310 XplatUIWin32.RECT BoundsRect;
312 last_hresult = UXTheme.GetThemeMargins (theme, dc.GetHdc (), this.part, this.state, (int)prop, out BoundsRect, out retval);
315 return retval.ToPadding();
318 public Size GetPartSize (IDeviceContext dc, Rectangle bounds, ThemeSizeType type)
321 throw new ArgumentNullException ("dc");
322 if (!Enum.IsDefined (typeof (ThemeSizeType), type))
323 throw new System.ComponentModel.InvalidEnumArgumentException ("prop", (int)type, typeof (ThemeSizeType));
325 XplatUIWin32.RECT BoundsRect = XplatUIWin32.RECT.FromRectangle (bounds);
328 last_hresult = UXTheme.GetThemePartSize (theme, dc.GetHdc (), this.part, this.state, ref BoundsRect, (int)type, out retval);
331 return retval.ToSize();
334 public Size GetPartSize (IDeviceContext dc, ThemeSizeType type)
337 throw new ArgumentNullException ("dc");
338 if (!Enum.IsDefined (typeof (ThemeSizeType), type))
339 throw new System.ComponentModel.InvalidEnumArgumentException ("prop", (int)type, typeof (ThemeSizeType));
343 last_hresult = UXTheme.GetThemePartSize (theme, dc.GetHdc (), this.part, this.state, 0, (int)type, out retval);
346 return retval.ToSize ();
349 public Point GetPoint (PointProperty prop)
351 if (!Enum.IsDefined (typeof (PointProperty), prop))
352 throw new System.ComponentModel.InvalidEnumArgumentException ("prop", (int)prop, typeof (PointProperty));
355 last_hresult = UXTheme.GetThemePosition (theme, this.part, this.state, (int)prop, out retval);
357 return retval.ToPoint();
360 [MonoTODO(@"Can't find any values that return anything on MS to test against")]
361 public string GetString (StringProperty prop)
363 if (!Enum.IsDefined (typeof (StringProperty), prop))
364 throw new System.ComponentModel.InvalidEnumArgumentException ("prop", (int)prop, typeof (StringProperty));
366 Text.StringBuilder sb = new Text.StringBuilder (255);
367 last_hresult = UXTheme.GetThemeString (theme, this.part, this.state, (int)prop, sb, sb.Capacity);
369 return sb.ToString ();
372 public Rectangle GetTextExtent (IDeviceContext dc, Rectangle bounds, string textToDraw, TextFormatFlags flags)
375 throw new ArgumentNullException ("dc");
377 XplatUIWin32.RECT BoundsRect = XplatUIWin32.RECT.FromRectangle (bounds);
378 XplatUIWin32.RECT retval;
380 last_hresult = UXTheme.GetThemeTextExtent (theme, dc.GetHdc (), this.part, this.state, textToDraw, textToDraw.Length, (int)flags, ref BoundsRect, out retval);
383 return retval.ToRectangle ();
386 public Rectangle GetTextExtent (IDeviceContext dc, string textToDraw, TextFormatFlags flags)
389 throw new ArgumentNullException ("dc");
391 XplatUIWin32.RECT retval;
393 last_hresult = UXTheme.GetThemeTextExtent (theme, dc.GetHdc (), this.part, this.state, textToDraw, textToDraw.Length, (int)flags, 0, out retval);
396 return retval.ToRectangle ();
399 public TextMetrics GetTextMetrics (IDeviceContext dc)
402 throw new ArgumentNullException ("dc", "dc cannot be null.");
404 XplatUIWin32.TEXTMETRIC metrics;
406 last_hresult = UXTheme.GetThemeTextMetrics (theme, dc.GetHdc (), this.part, this.state, out metrics);
409 TextMetrics retval = new TextMetrics ();
410 retval.Ascent = metrics.tmAscent;
411 retval.AverageCharWidth = metrics.tmAveCharWidth;
412 retval.BreakChar =(char)metrics.tmBreakChar;
413 retval.CharSet = (TextMetricsCharacterSet)metrics.tmCharSet;
414 retval.DefaultChar = (char)metrics.tmDefaultChar;
415 retval.Descent = metrics.tmDescent;
416 retval.DigitizedAspectX = metrics.tmDigitizedAspectX;
417 retval.DigitizedAspectY = metrics.tmDigitizedAspectY;
418 retval.ExternalLeading = metrics.tmExternalLeading;
419 retval.FirstChar = (char)metrics.tmFirstChar;
420 retval.Height = metrics.tmHeight;
421 retval.InternalLeading = metrics.tmInternalLeading;
422 retval.Italic = metrics.tmItalic == 0 ? false : true;
423 retval.LastChar = (char)metrics.tmLastChar;
424 retval.MaxCharWidth = metrics.tmMaxCharWidth;
425 retval.Overhang = metrics.tmOverhang;
426 retval.PitchAndFamily = (TextMetricsPitchAndFamilyValues)metrics.tmPitchAndFamily;
427 retval.StruckOut = metrics.tmStruckOut == 0 ? false : true;
428 retval.Underlined = metrics.tmUnderlined == 0 ? false : true;
429 retval.Weight = metrics.tmWeight;
434 public HitTestCode HitTestBackground (IDeviceContext dc, Rectangle backgroundRectangle, IntPtr hRgn, Point pt, HitTestOptions options)
437 throw new ArgumentNullException ("dc");
439 XplatUIWin32.RECT BoundsRect = XplatUIWin32.RECT.FromRectangle (backgroundRectangle);
442 last_hresult = UXTheme.HitTestThemeBackground (theme, dc.GetHdc (), this.part, this.state, (uint)options, ref BoundsRect, hRgn, new POINT(pt.X, pt.Y), out retval);
445 return (HitTestCode)retval;
448 public HitTestCode HitTestBackground (Graphics g, Rectangle backgroundRectangle, Region region, Point pt, HitTestOptions options)
451 throw new ArgumentNullException ("g");
453 IntPtr hRgn = region.GetHrgn(g);
455 return this.HitTestBackground(g, backgroundRectangle, hRgn, pt, options);
458 public HitTestCode HitTestBackground (IDeviceContext dc, Rectangle backgroundRectangle, Point pt, HitTestOptions options)
460 return this.HitTestBackground (dc, backgroundRectangle, IntPtr.Zero, pt, options);
463 public bool IsBackgroundPartiallyTransparent ()
465 int retval = UXTheme.IsThemeBackgroundPartiallyTransparent (theme, this.part, this.state);
467 return retval == 0 ? false : true;
470 public void SetParameters (string className, int part, int state)
472 if (theme != IntPtr.Zero)
473 last_hresult = UXTheme.CloseThemeData (theme);
476 throw new InvalidOperationException ("Visual Styles are not enabled.");
478 this.class_name = className;
481 theme = UXTheme.OpenThemeData (IntPtr.Zero, this.class_name);
483 if (!UXTheme.IsThemePartDefined (theme, this.part, 0))
484 throw new ArgumentException ("This element is not supported by the current visual style.");
487 public void SetParameters (VisualStyleElement element)
489 this.SetParameters (element.ClassName, element.Part, element.State);