New test.
[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 #if NET_2_0
30 using System.Drawing;
31
32 namespace System.Windows.Forms.VisualStyles
33 {
34         public sealed class VisualStyleRenderer
35         {
36                 private string class_name;
37                 private int part;
38                 private int state;
39                 private IntPtr theme;
40                 private int last_hresult = 0;
41
42                 #region Public Constructors
43                 public VisualStyleRenderer (string className, int part, int state)
44                 {
45                         this.SetParameters (className, part, state);
46                 }
47
48                 public VisualStyleRenderer (VisualStyleElement element)
49                 {
50                         this.SetParameters (element);
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                         IntPtr theme = UXTheme.OpenThemeData (IntPtr.Zero, element.ClassName);
82                         bool retval = UXTheme.IsThemePartDefined (theme, element.Part, 0);
83                         UXTheme.CloseThemeData (theme);
84
85                         return retval;
86                 }
87                 #endregion
88
89                 #region Public Instance Methods
90                 public void DrawBackground (IDeviceContext dc, Rectangle bounds)
91                 {
92                         if (dc == null)
93                                 throw new ArgumentNullException ("dc");
94
95                         UXTheme.RECT BoundsRect = UXTheme.RECT.FromRectangle (bounds);
96
97                         last_hresult = UXTheme.DrawThemeBackground (theme, dc.GetHdc (), this.part, this.state, ref BoundsRect, IntPtr.Zero);
98                         dc.ReleaseHdc ();
99                 }
100
101                 public void DrawBackground (IDeviceContext dc, Rectangle bounds, Rectangle clipRectangle)
102                 {
103                         if (dc == null)
104                                 throw new ArgumentNullException ("dc");
105
106                         UXTheme.RECT BoundsRect = UXTheme.RECT.FromRectangle (bounds);
107                         UXTheme.RECT ClipRect = UXTheme.RECT.FromRectangle (clipRectangle);
108
109                         last_hresult = UXTheme.DrawThemeBackground (theme, dc.GetHdc (), this.part, this.state, ref BoundsRect, ref ClipRect);
110                         dc.ReleaseHdc ();
111                 }
112
113                 public Rectangle DrawEdge (IDeviceContext dc, Rectangle bounds, Edges edges, EdgeStyle style, EdgeEffects effects)
114                 {
115                         if (dc == null)
116                                 throw new ArgumentNullException ("dc");
117
118                         UXTheme.RECT BoundsRect = UXTheme.RECT.FromRectangle (bounds);
119                         UXTheme.RECT retval;
120
121                         last_hresult = UXTheme.DrawThemeEdge (theme, dc.GetHdc (), this.part, this.state, ref BoundsRect, (uint)style, (uint)edges + (uint)effects, out retval);
122                         dc.ReleaseHdc ();
123                         return retval.ToRectangle ();
124                 }
125
126                 public void DrawImage (Graphics g, Rectangle bounds, ImageList imageList, int imageIndex)
127                 {
128                         if (g == null)
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");
134
135                         g.DrawImage (imageList.Images[imageIndex], bounds);
136                 }
137
138                 public void DrawImage (Graphics g, Rectangle bounds, Image image)
139                 {
140                         if (g == null)
141                                 throw new ArgumentNullException ("g");
142                         if (image == null)
143                                 throw new ArgumentNullException ("image");
144
145                         g.DrawImage (image, bounds);
146                 }
147
148                 public void DrawParentBackground (IDeviceContext dc, Rectangle bounds, Control childControl)
149                 {
150                         if (dc == null)
151                                 throw new ArgumentNullException ("dc");
152
153                         UXTheme.RECT BoundsRect = UXTheme.RECT.FromRectangle (bounds);
154
155                         using (Graphics g = Graphics.FromHwnd (childControl.Handle)) {
156                                 last_hresult = UXTheme.DrawThemeParentBackground (childControl.Handle, g.GetHdc (), ref BoundsRect);
157                                 g.ReleaseHdc ();
158                         }
159                 }
160
161                 public void DrawText (IDeviceContext dc, Rectangle bounds, string textToDraw, bool drawDisabled, TextFormatFlags flags)
162                 {
163                         if (dc == null)
164                                 throw new ArgumentNullException ("dc");
165
166                         UXTheme.RECT BoundsRect = UXTheme.RECT.FromRectangle (bounds);
167
168                         last_hresult = UXTheme.DrawThemeText (theme, dc.GetHdc (), this.part, this.state, textToDraw, textToDraw.Length, (uint)flags, 0, ref BoundsRect);
169                         dc.ReleaseHdc ();
170                 }
171
172                 public void DrawText (IDeviceContext dc, Rectangle bounds, string textToDraw, bool drawDisabled)
173                 {
174                         this.DrawText (dc, bounds, textToDraw, drawDisabled, TextFormatFlags.Default);
175                 }
176
177                 public void DrawText (IDeviceContext dc, Rectangle bounds, string textToDraw)
178                 {
179                         this.DrawText (dc, bounds, textToDraw, false, TextFormatFlags.Default);
180                 }
181
182                 public Rectangle GetBackgroundContentRectangle (IDeviceContext dc, Rectangle bounds)
183                 {
184                         if (dc == null)
185                                 throw new ArgumentNullException ("dc");
186
187                         UXTheme.RECT BoundsRect = UXTheme.RECT.FromRectangle (bounds);
188                         UXTheme.RECT retval;
189
190                         last_hresult = UXTheme.GetThemeBackgroundContentRect (theme, dc.GetHdc (), this.part, this.state, ref BoundsRect, out retval);
191                         dc.ReleaseHdc ();
192
193                         return retval.ToRectangle ();
194                 }
195
196                 public Rectangle GetBackgroundExtent (IDeviceContext dc, Rectangle contentBounds)
197                 {
198                         if (dc == null)
199                                 throw new ArgumentNullException ("dc");
200
201                         UXTheme.RECT BoundsRect = UXTheme.RECT.FromRectangle (contentBounds);
202                         UXTheme.RECT retval = new UXTheme.RECT ();
203
204                         last_hresult = UXTheme.GetThemeBackgroundExtent (theme, dc.GetHdc (), this.part, this.state, ref BoundsRect, ref retval);
205                         dc.ReleaseHdc ();
206
207                         return retval.ToRectangle ();
208                 }
209
210                 [System.Security.SuppressUnmanagedCodeSecurity]
211                 public Region GetBackgroundRegion (IDeviceContext dc, Rectangle contentBounds)
212                 {
213                         if (dc == null)
214                                 throw new ArgumentNullException ("dc");
215
216                         UXTheme.RECT BoundsRect = UXTheme.RECT.FromRectangle (contentBounds);
217                         IntPtr retval;
218
219                         last_hresult = UXTheme.GetThemeBackgroundRegion (theme, dc.GetHdc (), this.part, this.state, ref BoundsRect, out retval);
220                         dc.ReleaseHdc ();
221
222                         return Region.FromHrgn (retval);
223                 }
224
225                 public bool GetBoolean (BooleanProperty prop)
226                 {
227                         if (!Enum.IsDefined (typeof (BooleanProperty), prop))
228                                 throw new System.ComponentModel.InvalidEnumArgumentException ("prop", (int)prop, typeof (BooleanProperty));
229
230                         int retval;
231                         last_hresult = UXTheme.GetThemeBool (theme, this.part, this.state, (int)prop, out retval);
232
233                         return retval == 0 ? false : true;
234                 }
235
236                 public Color GetColor (ColorProperty prop)
237                 {
238                         if (!Enum.IsDefined (typeof (ColorProperty), prop))
239                                 throw new System.ComponentModel.InvalidEnumArgumentException ("prop", (int)prop, typeof (ColorProperty));
240
241                         int retval;
242                         last_hresult = UXTheme.GetThemeColor (theme, this.part, this.state, (int)prop, out retval);
243
244                         return System.Drawing.Color.FromArgb ((int)(0x000000FFU & retval),
245                              (int)(0x0000FF00U & retval) >> 8, (int)(0x00FF0000U & retval) >> 16);
246                 }
247                 
248                 public int GetEnumValue (EnumProperty prop)
249                 {
250                         if (!Enum.IsDefined (typeof (EnumProperty), prop))
251                                 throw new System.ComponentModel.InvalidEnumArgumentException ("prop", (int)prop, typeof (EnumProperty));
252
253                         int retval;
254                         last_hresult = UXTheme.GetThemeEnumValue (theme, this.part, this.state, (int)prop, out retval);
255
256                         return retval;
257                 }
258                 
259                 public string GetFilename (FilenameProperty prop)
260                 {
261                         if (!Enum.IsDefined (typeof (FilenameProperty), prop))
262                                 throw new System.ComponentModel.InvalidEnumArgumentException ("prop", (int)prop, typeof (FilenameProperty));
263
264                         Text.StringBuilder sb = new Text.StringBuilder (255);
265                         last_hresult = UXTheme.GetThemeFilename (theme, this.part, this.state, (int)prop, sb, sb.Capacity);
266
267                         return sb.ToString ();
268                 }
269                 
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)
272                 {
273                         throw new NotImplementedException();
274                         //if (dc == null)
275                         //        throw new ArgumentNullException ("dc");
276                         //if (!Enum.IsDefined (typeof (FontProperty), prop))
277                         //        throw new System.ComponentModel.InvalidEnumArgumentException ("prop", (int)prop, typeof (FontProperty));
278
279                         //UXTheme.LOGFONT lf = new UXTheme.LOGFONT();
280
281                         //UXTheme.GetThemeFont (theme, dc.GetHdc (), this.part, this.state, (int)prop, out lf);
282                         //IntPtr fontPtr = UXTheme.CreateFontIndirect(lf);
283                         //dc.ReleaseHdc();
284
285                         //return Font.FromLogFont(lf);
286                         //return null;
287                 }
288                 
289                 public int GetInteger (IntegerProperty prop)
290                 {
291                         if (!Enum.IsDefined (typeof (IntegerProperty), prop))
292                                 throw new System.ComponentModel.InvalidEnumArgumentException ("prop", (int)prop, typeof (IntegerProperty));
293
294                         int retval;
295                         last_hresult = UXTheme.GetThemeInt (theme, this.part, this.state, (int)prop, out retval);
296
297                         return retval;
298                 }
299                 
300                 [MonoTODO(@"MS's causes a PInvokeStackUnbalance on me, so this is not verified against MS.")]
301                 public Padding GetMargins (IDeviceContext dc, MarginProperty prop)
302                 {
303                         if (dc == null)
304                                 throw new ArgumentNullException ("dc");
305                         if (!Enum.IsDefined (typeof (MarginProperty), prop))
306                                 throw new System.ComponentModel.InvalidEnumArgumentException ("prop", (int)prop, typeof (MarginProperty));
307
308
309                         UXTheme.MARGINS retval = new UXTheme.MARGINS ();
310                         UXTheme.RECT BoundsRect;
311
312                         last_hresult = UXTheme.GetThemeMargins (theme, dc.GetHdc (), this.part, this.state, (int)prop, out BoundsRect, out retval);
313                         dc.ReleaseHdc ();
314
315                         return retval.ToPadding();
316                 }
317                 
318                 public Size GetPartSize (IDeviceContext dc, Rectangle bounds, ThemeSizeType type)
319                 {
320                         if (dc == null)
321                                 throw new ArgumentNullException ("dc");
322                         if (!Enum.IsDefined (typeof (ThemeSizeType), type))
323                                 throw new System.ComponentModel.InvalidEnumArgumentException ("prop", (int)type, typeof (ThemeSizeType));
324
325                         UXTheme.RECT BoundsRect = UXTheme.RECT.FromRectangle (bounds);
326                         UXTheme.SIZE retval;
327
328                         last_hresult = UXTheme.GetThemePartSize (theme, dc.GetHdc (), this.part, this.state, ref BoundsRect, (int)type, out retval);
329                         dc.ReleaseHdc ();
330
331                         return retval.ToSize();
332                 }
333
334                 public Size GetPartSize (IDeviceContext dc, ThemeSizeType type)
335                 {
336                         if (dc == null)
337                                 throw new ArgumentNullException ("dc");
338                         if (!Enum.IsDefined (typeof (ThemeSizeType), type))
339                                 throw new System.ComponentModel.InvalidEnumArgumentException ("prop", (int)type, typeof (ThemeSizeType));
340
341                         UXTheme.SIZE retval;
342
343                         last_hresult = UXTheme.GetThemePartSize (theme, dc.GetHdc (), this.part, this.state, 0, (int)type, out retval);
344                         dc.ReleaseHdc ();
345
346                         return retval.ToSize ();
347                 }
348
349                 public Point GetPoint (PointProperty prop)
350                 {
351                         if (!Enum.IsDefined (typeof (PointProperty), prop))
352                                 throw new System.ComponentModel.InvalidEnumArgumentException ("prop", (int)prop, typeof (PointProperty));
353
354                         UXTheme.POINT retval;
355                         last_hresult = UXTheme.GetThemePosition (theme, this.part, this.state, (int)prop, out retval);
356
357                         return retval.ToPoint();
358                 }
359                 
360                 [MonoTODO(@"Can't find any values that return anything on MS to test against")]
361                 public string GetString (StringProperty prop)
362                 {
363                         if (!Enum.IsDefined (typeof (StringProperty), prop))
364                                 throw new System.ComponentModel.InvalidEnumArgumentException ("prop", (int)prop, typeof (StringProperty));
365
366                         Text.StringBuilder sb = new Text.StringBuilder (255);
367                         last_hresult = UXTheme.GetThemeString (theme, this.part, this.state, (int)prop, sb, sb.Capacity);
368
369                         return sb.ToString ();
370                 }
371                 
372                 public Rectangle GetTextExtent (IDeviceContext dc, Rectangle bounds, string textToDraw, TextFormatFlags flags)
373                 {
374                         if (dc == null)
375                                 throw new ArgumentNullException ("dc");
376
377                         UXTheme.RECT BoundsRect = UXTheme.RECT.FromRectangle (bounds);
378                         UXTheme.RECT retval;
379                         
380                         last_hresult = UXTheme.GetThemeTextExtent (theme, dc.GetHdc (), this.part, this.state, textToDraw, textToDraw.Length, (int)flags, ref BoundsRect, out retval);
381                         dc.ReleaseHdc ();
382
383                         return retval.ToRectangle ();
384                 }
385
386                 public Rectangle GetTextExtent (IDeviceContext dc, string textToDraw, TextFormatFlags flags)
387                 {
388                         if (dc == null)
389                                 throw new ArgumentNullException ("dc");
390
391                         UXTheme.RECT retval;
392                         
393                         last_hresult = UXTheme.GetThemeTextExtent (theme, dc.GetHdc (), this.part, this.state, textToDraw, textToDraw.Length, (int)flags, 0, out retval);
394                         dc.ReleaseHdc ();
395
396                         return retval.ToRectangle ();
397                 }
398                 
399                 public TextMetrics GetTextMetrics (IDeviceContext dc)
400                 {
401                         if (dc == null)
402                                 throw new ArgumentNullException ("dc", "dc cannot be null.");
403
404                         UXTheme.TEXTMETRIC metrics;
405                         
406                         last_hresult = UXTheme.GetThemeTextMetrics (theme, dc.GetHdc (), this.part, this.state, out metrics);
407                         dc.ReleaseHdc ();
408
409                         TextMetrics retval = new TextMetrics ();
410                         retval.Ascent = metrics.tmAscent;
411                         retval.AverageCharWidth = metrics.tmAveCharWidth;
412                         retval.BreakChar = metrics.tmBreakChar;
413                         retval.CharSet = (TextMetricsCharacterSet)metrics.tmCharSet;
414                         retval.DefaultChar = 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 = metrics.tmFirstChar;
420                         retval.Height = metrics.tmHeight;
421                         retval.InternalLeading = metrics.tmInternalLeading;
422                         retval.Italic = metrics.tmItalic == 0 ? false : true;
423                         retval.LastChar = 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;
430
431                         return retval;
432                 }
433
434                 public HitTestCode HitTestBackground (IDeviceContext dc, Rectangle backgroundRectangle, IntPtr hRgn, Point pt, HitTestOptions options)
435                 {
436                         if (dc == null)
437                                 throw new ArgumentNullException ("dc");
438
439                         UXTheme.RECT BoundsRect = UXTheme.RECT.FromRectangle (backgroundRectangle);
440                         int retval;
441
442                         last_hresult = UXTheme.HitTestThemeBackground (theme, dc.GetHdc (), this.part, this.state, (uint)options, ref BoundsRect, hRgn, new UXTheme.POINT(pt.X, pt.Y), out retval);
443                         dc.ReleaseHdc ();
444
445                         return (HitTestCode)retval;
446                 }
447
448                 public HitTestCode HitTestBackground (Graphics g, Rectangle backgroundRectangle, Region region, Point pt, HitTestOptions options)
449                 {
450                         if (g == null)
451                                 throw new ArgumentNullException ("g");
452
453                         IntPtr hRgn = region.GetHrgn(g);
454                         
455                         return this.HitTestBackground(g, backgroundRectangle, hRgn, pt, options);
456                 }
457
458                 public HitTestCode HitTestBackground (IDeviceContext dc, Rectangle backgroundRectangle, Point pt, HitTestOptions options)
459                 {
460                         return this.HitTestBackground (dc, backgroundRectangle, IntPtr.Zero, pt, options);
461                 }
462
463                 public bool IsBackgroundPartiallyTransparent ()
464                 {
465                         int retval = UXTheme.IsThemeBackgroundPartiallyTransparent (theme, this.part, this.state);
466
467                         return retval == 0 ? false : true;
468                 }
469
470                 public void SetParameters (string className, int part, int state)
471                 {
472                         if (theme != IntPtr.Zero)
473                                 last_hresult = UXTheme.CloseThemeData (theme);
474
475                         if (!IsSupported)
476                                 throw new InvalidOperationException ("Visual Styles are not enabled.");
477
478                         this.class_name = className;
479                         this.part = part;
480                         this.state = state;
481                         theme = UXTheme.OpenThemeData (IntPtr.Zero, this.class_name);
482
483                         if (!UXTheme.IsThemePartDefined (theme, this.part, 0))
484                                 throw new ArgumentException ("This element is not supported by the current visual style.");
485                 }
486
487                 public void SetParameters (VisualStyleElement element)
488                 {
489                         this.SetParameters (element.ClassName, element.Part, element.State);
490                 }
491                 #endregion
492         }
493 }
494 #endif