Merge pull request #1068 from esdrubal/bug18421
[mono.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms.VisualStyles / VisualStyleRenderer.cs
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
43                 public VisualStyleRenderer (string className, int part, int state)
44                 {
45                         theme_handle_manager.VisualStyleRenderer = this;
46                         this.SetParameters (className, part, state);
47                 }
48
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
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
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
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
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
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
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
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
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
159                 public void DrawText (IDeviceContext dc, Rectangle bounds, string textToDraw, bool drawDisabled)
160                 {
161                         this.DrawText (dc, bounds, textToDraw, drawDisabled, TextFormatFlags.Default);
162                 }
163
164                 public void DrawText (IDeviceContext dc, Rectangle bounds, string textToDraw)
165                 {
166                         this.DrawText (dc, bounds, textToDraw, false, TextFormatFlags.Default);
167                 }
168
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
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]
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
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
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                 
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                 
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")]
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                 
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.")]
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                 
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
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
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")]
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                 
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
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                 
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
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
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
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
383                 public bool IsBackgroundPartiallyTransparent ()
384                 {
385                         return VisualStyles.UxThemeIsThemeBackgroundPartiallyTransparent (theme, this.part, this.state);
386                 }
387
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
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
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
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;
437                         ~ThemeHandleManager ()
438                         {
439                                 if (VisualStyleRenderer.theme == IntPtr.Zero)
440                                         return;
441                                 VisualStyles.UxThemeCloseThemeData (VisualStyleRenderer.theme);
442                         }
443                 }
444                 #endregion
445         }
446 }