// // VisualStylesNative.cs: IVisualStyles that uses the Visual Styles feature of // Windows XP and later. // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the // "Software"), to deal in the Software without restriction, including // without limitation the rights to use, copy, modify, merge, publish, // distribute, sublicense, and/or sell copies of the Software, and to // permit persons to whom the Software is furnished to do so, subject to // the following conditions: // // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // // Copyright (c) 2006 Novell, Inc. // // Authors: // Jonathan Pobst (monkey@jpobst.com) // using System.Drawing; using System.Diagnostics; namespace System.Windows.Forms.VisualStyles { class VisualStylesNative : IVisualStyles { #region UxTheme public int UxThemeCloseThemeData (IntPtr hTheme) { return UXTheme.CloseThemeData (hTheme); } public int UxThemeDrawThemeBackground (IntPtr hTheme, IDeviceContext dc, int iPartId, int iStateId, Rectangle bounds) { XplatUIWin32.RECT BoundsRect = XplatUIWin32.RECT.FromRectangle (bounds); int result = UXTheme.DrawThemeBackground(hTheme, dc.GetHdc (), iPartId, iStateId, ref BoundsRect, IntPtr.Zero); dc.ReleaseHdc (); return result; } public int UxThemeDrawThemeBackground (IntPtr hTheme, IDeviceContext dc, int iPartId, int iStateId, Rectangle bounds, Rectangle clipRectangle) { XplatUIWin32.RECT BoundsRect = XplatUIWin32.RECT.FromRectangle (bounds); XplatUIWin32.RECT ClipRect = XplatUIWin32.RECT.FromRectangle (clipRectangle); int result = UXTheme.DrawThemeBackground (hTheme, dc.GetHdc (), iPartId, iStateId, ref BoundsRect, ref ClipRect); dc.ReleaseHdc (); return result; } public int UxThemeDrawThemeEdge (IntPtr hTheme, IDeviceContext dc, int iPartId, int iStateId, Rectangle bounds, Edges edges, EdgeStyle style, EdgeEffects effects, out Rectangle result) { XplatUIWin32.RECT BoundsRect = XplatUIWin32.RECT.FromRectangle (bounds); XplatUIWin32.RECT retval; int hresult = UXTheme.DrawThemeEdge (hTheme, dc.GetHdc (), iPartId, iStateId, ref BoundsRect, (uint)style, (uint)edges + (uint)effects, out retval); dc.ReleaseHdc (); result = retval.ToRectangle(); return hresult; } public int UxThemeDrawThemeParentBackground (IDeviceContext dc, Rectangle bounds, Control childControl) { int result; XplatUIWin32.RECT BoundsRect = XplatUIWin32.RECT.FromRectangle (bounds); using (Graphics g = Graphics.FromHwnd (childControl.Handle)) { IntPtr hdc = g.GetHdc (); result = UXTheme.DrawThemeParentBackground (childControl.Handle, hdc, ref BoundsRect); g.ReleaseHdc (hdc); } return result; } public int UxThemeDrawThemeText (IntPtr hTheme, IDeviceContext dc, int iPartId, int iStateId, string text, TextFormatFlags textFlags, Rectangle bounds) { XplatUIWin32.RECT BoundsRect = XplatUIWin32.RECT.FromRectangle (bounds); int result = UXTheme.DrawThemeText (hTheme, dc.GetHdc (), iPartId, iStateId, text, text.Length, (uint)textFlags, 0, ref BoundsRect); dc.ReleaseHdc (); return result; } public int UxThemeGetThemeBackgroundContentRect (IntPtr hTheme, IDeviceContext dc, int iPartId, int iStateId, Rectangle bounds, out Rectangle result) { XplatUIWin32.RECT BoundsRect = XplatUIWin32.RECT.FromRectangle (bounds); XplatUIWin32.RECT retval; int hresult = UXTheme.GetThemeBackgroundContentRect (hTheme, dc.GetHdc (), iPartId, iStateId, ref BoundsRect, out retval); dc.ReleaseHdc (); result = retval.ToRectangle (); return hresult; } public int UxThemeGetThemeBackgroundExtent (IntPtr hTheme, IDeviceContext dc, int iPartId, int iStateId, Rectangle contentBounds, out Rectangle result) { XplatUIWin32.RECT BoundsRect = XplatUIWin32.RECT.FromRectangle (contentBounds); XplatUIWin32.RECT retval = new XplatUIWin32.RECT (); int hresult = UXTheme.GetThemeBackgroundExtent (hTheme, dc.GetHdc (), iPartId, iStateId, ref BoundsRect, ref retval); dc.ReleaseHdc (); result = retval.ToRectangle (); return hresult; } public int UxThemeGetThemeBackgroundRegion (IntPtr hTheme, IDeviceContext dc, int iPartId, int iStateId, Rectangle bounds, out Region result) { XplatUIWin32.RECT BoundsRect = XplatUIWin32.RECT.FromRectangle (bounds); IntPtr retval; int hresult = UXTheme.GetThemeBackgroundRegion (hTheme, dc.GetHdc (), iPartId, iStateId, ref BoundsRect, out retval); dc.ReleaseHdc (); result = Region.FromHrgn (retval); return hresult; } public int UxThemeGetThemeBool (IntPtr hTheme, int iPartId, int iStateId, BooleanProperty prop, out bool result) { int retval; int hresult = UXTheme.GetThemeBool (hTheme, iPartId, iStateId, (int)prop, out retval); result = retval == 0 ? false : true; return hresult; } public int UxThemeGetThemeColor (IntPtr hTheme, int iPartId, int iStateId, ColorProperty prop, out Color result) { int retval; int hresult = UXTheme.GetThemeColor (hTheme, iPartId, iStateId, (int)prop, out retval); result = System.Drawing.Color.FromArgb ((int)(0x000000FFU & retval), (int)(0x0000FF00U & retval) >> 8, (int)(0x00FF0000U & retval) >> 16); return hresult; } public int UxThemeGetThemeEnumValue (IntPtr hTheme, int iPartId, int iStateId, EnumProperty prop, out int result) { int retval; int hresult = UXTheme.GetThemeEnumValue (hTheme, iPartId, iStateId, (int)prop, out retval); result = retval; return hresult; } public int UxThemeGetThemeFilename (IntPtr hTheme, int iPartId, int iStateId, FilenameProperty prop, out string result) { Text.StringBuilder sb = new Text.StringBuilder (255); int hresult = UXTheme.GetThemeFilename (hTheme, iPartId, iStateId, (int)prop, sb, sb.Capacity); result = sb.ToString (); return hresult; } public int UxThemeGetThemeInt (IntPtr hTheme, int iPartId, int iStateId, IntegerProperty prop, out int result) { int retval; int hresult = UXTheme.GetThemeInt (hTheme, iPartId, iStateId, (int)prop, out retval); result = retval; return hresult; } public int UxThemeGetThemeMargins (IntPtr hTheme, IDeviceContext dc, int iPartId, int iStateId, MarginProperty prop, out Padding result) { UXTheme.MARGINS retval = new UXTheme.MARGINS (); XplatUIWin32.RECT BoundsRect; int hresult = UXTheme.GetThemeMargins (hTheme, dc.GetHdc (), iPartId, iStateId, (int)prop, out BoundsRect, out retval); dc.ReleaseHdc (); result = retval.ToPadding(); return hresult; } public int UxThemeGetThemePartSize (IntPtr hTheme, IDeviceContext dc, int iPartId, int iStateId, Rectangle bounds, ThemeSizeType type, out Size result) { XplatUIWin32.RECT BoundsRect = XplatUIWin32.RECT.FromRectangle (bounds); UXTheme.SIZE retval; int hresult = UXTheme.GetThemePartSize (hTheme, dc.GetHdc (), iPartId, iStateId, ref BoundsRect, (int)type, out retval); dc.ReleaseHdc (); result = retval.ToSize(); return hresult; } public int UxThemeGetThemePartSize (IntPtr hTheme, IDeviceContext dc, int iPartId, int iStateId, ThemeSizeType type, out Size result) { UXTheme.SIZE retval; int hresult = UXTheme.GetThemePartSize (hTheme, dc.GetHdc (), iPartId, iStateId, IntPtr.Zero, (int)type, out retval); dc.ReleaseHdc (); result = retval.ToSize (); return hresult; } public int UxThemeGetThemePosition (IntPtr hTheme, int iPartId, int iStateId, PointProperty prop, out Point result) { POINT retval; int hresult = UXTheme.GetThemePosition (hTheme, iPartId, iStateId, (int)prop, out retval); result = retval.ToPoint(); return hresult; } public int UxThemeGetThemeString (IntPtr hTheme, int iPartId, int iStateId, StringProperty prop, out string result) { Text.StringBuilder sb = new Text.StringBuilder (255); int hresult = UXTheme.GetThemeString (hTheme, iPartId, iStateId, (int)prop, sb, sb.Capacity); result = sb.ToString (); return hresult; } public int UxThemeGetThemeTextExtent (IntPtr hTheme, IDeviceContext dc, int iPartId, int iStateId, string textToDraw, TextFormatFlags flags, Rectangle bounds, out Rectangle result) { XplatUIWin32.RECT BoundsRect = XplatUIWin32.RECT.FromRectangle (bounds); XplatUIWin32.RECT retval; int hresult = UXTheme.GetThemeTextExtent (hTheme, dc.GetHdc (), iPartId, iStateId, textToDraw, textToDraw.Length, (int)flags, ref BoundsRect, out retval); dc.ReleaseHdc (); result = retval.ToRectangle (); return hresult; } public int UxThemeGetThemeTextExtent (IntPtr hTheme, IDeviceContext dc, int iPartId, int iStateId, string textToDraw, TextFormatFlags flags, out Rectangle result) { XplatUIWin32.RECT retval; int hresult = UXTheme.GetThemeTextExtent (hTheme, dc.GetHdc (), iPartId, iStateId, textToDraw, textToDraw.Length, (int)flags, 0, out retval); dc.ReleaseHdc (); result = retval.ToRectangle (); return hresult; } public int UxThemeGetThemeTextMetrics (IntPtr hTheme, IDeviceContext dc, int iPartId, int iStateId, out TextMetrics result) { XplatUIWin32.TEXTMETRIC metrics; int hresult = UXTheme.GetThemeTextMetrics (hTheme, dc.GetHdc (), iPartId, iStateId, out metrics); dc.ReleaseHdc (); TextMetrics retval = new TextMetrics (); retval.Ascent = metrics.tmAscent; retval.AverageCharWidth = metrics.tmAveCharWidth; retval.BreakChar =(char)metrics.tmBreakChar; retval.CharSet = (TextMetricsCharacterSet)metrics.tmCharSet; retval.DefaultChar = (char)metrics.tmDefaultChar; retval.Descent = metrics.tmDescent; retval.DigitizedAspectX = metrics.tmDigitizedAspectX; retval.DigitizedAspectY = metrics.tmDigitizedAspectY; retval.ExternalLeading = metrics.tmExternalLeading; retval.FirstChar = (char)metrics.tmFirstChar; retval.Height = metrics.tmHeight; retval.InternalLeading = metrics.tmInternalLeading; retval.Italic = metrics.tmItalic == 0 ? false : true; retval.LastChar = (char)metrics.tmLastChar; retval.MaxCharWidth = metrics.tmMaxCharWidth; retval.Overhang = metrics.tmOverhang; retval.PitchAndFamily = (TextMetricsPitchAndFamilyValues)metrics.tmPitchAndFamily; retval.StruckOut = metrics.tmStruckOut == 0 ? false : true; retval.Underlined = metrics.tmUnderlined == 0 ? false : true; retval.Weight = metrics.tmWeight; result = retval; return hresult; } public int UxThemeHitTestThemeBackground (IntPtr hTheme, IDeviceContext dc, int iPartId, int iStateId, HitTestOptions options, Rectangle backgroundRectangle, IntPtr hrgn, Point pt, out HitTestCode result) { XplatUIWin32.RECT BoundsRect = XplatUIWin32.RECT.FromRectangle (backgroundRectangle); int retval; int hresult = UXTheme.HitTestThemeBackground (hTheme, dc.GetHdc (), iPartId, iStateId, (uint)options, ref BoundsRect, hrgn, new POINT(pt.X, pt.Y), out retval); dc.ReleaseHdc (); result = (HitTestCode)retval; return hresult; } public bool UxThemeIsAppThemed () { return UXTheme.IsAppThemed (); } public bool UxThemeIsThemeActive () { return UXTheme.IsThemeActive (); } public bool UxThemeIsThemePartDefined (IntPtr hTheme, int iPartId) { return UXTheme.IsThemePartDefined (hTheme, iPartId, 0); } public bool UxThemeIsThemeBackgroundPartiallyTransparent (IntPtr hTheme, int iPartId, int iStateId) { int retval = UXTheme.IsThemeBackgroundPartiallyTransparent (hTheme, iPartId, iStateId); return retval == 0 ? false : true; } public IntPtr UxThemeOpenThemeData (IntPtr hWnd, string classList) { return UXTheme.OpenThemeData (hWnd, classList); } #endregion #region VisualStyleInformation public string VisualStyleInformationAuthor { get { return GetData ("AUTHOR"); } } public string VisualStyleInformationColorScheme { get { Text.StringBuilder ThemeName = new Text.StringBuilder (260); Text.StringBuilder ColorName = new Text.StringBuilder (260); Text.StringBuilder SizeName = new Text.StringBuilder (260); UXTheme.GetCurrentThemeName (ThemeName, ThemeName.Capacity, ColorName, ColorName.Capacity, SizeName, SizeName.Capacity); return ColorName.ToString (); } } public string VisualStyleInformationCompany { get { return GetData ("COMPANY"); } } public Color VisualStyleInformationControlHighlightHot { get { IntPtr theme = UXTheme.OpenThemeData (IntPtr.Zero, "BUTTON"); uint retval = UXTheme.GetThemeSysColor (theme, 1621); UXTheme.CloseThemeData (theme); return System.Drawing.Color.FromArgb ((int)(0x000000FFU & retval), (int)(0x0000FF00U & retval) >> 8, (int)(0x00FF0000U & retval) >> 16); } } public string VisualStyleInformationCopyright { get { return GetData ("COPYRIGHT"); } } public string VisualStyleInformationDescription { get { return GetData ("DESCRIPTION"); } } public string VisualStyleInformationDisplayName { get { return GetData ("DISPLAYNAME"); } } public string VisualStyleInformationFileName { get { Text.StringBuilder ThemeName = new Text.StringBuilder (260); Text.StringBuilder ColorName = new Text.StringBuilder (260); Text.StringBuilder SizeName = new Text.StringBuilder (260); UXTheme.GetCurrentThemeName (ThemeName, ThemeName.Capacity, ColorName, ColorName.Capacity, SizeName, SizeName.Capacity); return ThemeName.ToString (); } } static string GetData (string propertyName) { Text.StringBuilder ThemeName = new Text.StringBuilder (260); Text.StringBuilder ColorName = new Text.StringBuilder (260); Text.StringBuilder SizeName = new Text.StringBuilder (260); UXTheme.GetCurrentThemeName (ThemeName, ThemeName.Capacity, ColorName, ColorName.Capacity, SizeName, SizeName.Capacity); Text.StringBuilder PropertyValue = new Text.StringBuilder (260); UXTheme.GetThemeDocumentationProperty (ThemeName.ToString(), propertyName, PropertyValue, PropertyValue.Capacity); return PropertyValue.ToString (); } public bool VisualStyleInformationIsSupportedByOS { get { return IsSupported (); } } public int VisualStyleInformationMinimumColorDepth { get { IntPtr theme = UXTheme.OpenThemeData (IntPtr.Zero, "BUTTON"); int retval; UXTheme.GetThemeSysInt (theme, 1301, out retval); UXTheme.CloseThemeData (theme); return retval; } } public static bool IsSupported () { // Supported OS's should be NT based and at least XP (XP, 2003, Vista) if ((Environment.OSVersion.Platform == PlatformID.Win32NT) && (Environment.OSVersion.Version >= new Version (5, 1))) return true; return false; } public string VisualStyleInformationSize { get { Text.StringBuilder ThemeName = new Text.StringBuilder (260); Text.StringBuilder ColorName = new Text.StringBuilder (260); Text.StringBuilder SizeName = new Text.StringBuilder (260); UXTheme.GetCurrentThemeName (ThemeName, ThemeName.Capacity, ColorName, ColorName.Capacity, SizeName, SizeName.Capacity); return SizeName.ToString (); } } public bool VisualStyleInformationSupportsFlatMenus { get { IntPtr theme = UXTheme.OpenThemeData (IntPtr.Zero, "BUTTON"); bool retval; retval = UXTheme.GetThemeSysBool (theme, 1001) == 0 ? false : true; UXTheme.CloseThemeData (theme); return retval; } } public Color VisualStyleInformationTextControlBorder { get { IntPtr theme = UXTheme.OpenThemeData (IntPtr.Zero, "EDIT"); uint retval = UXTheme.GetThemeSysColor (theme, 1611); UXTheme.CloseThemeData (theme); return System.Drawing.Color.FromArgb ((int)(0x000000FFU & retval), (int)(0x0000FF00U & retval) >> 8, (int)(0x00FF0000U & retval) >> 16); } } public string VisualStyleInformationUrl { get { return GetData ("URL"); } } public string VisualStyleInformationVersion { get { return GetData ("VERSION"); } } #endregion #region VisualStyleRenderer public void VisualStyleRendererDrawBackgroundExcludingArea (IntPtr theme, IDeviceContext dc, int part, int state, Rectangle bounds, Rectangle excludedArea) { XplatUIWin32.RECT bounds_rect = XplatUIWin32.RECT.FromRectangle (bounds); IntPtr hdc = dc.GetHdc (); XplatUIWin32.Win32ExcludeClipRect (hdc, excludedArea.Left, excludedArea.Top, excludedArea.Right, excludedArea.Bottom); UXTheme.DrawThemeBackground (theme, hdc, part, state, ref bounds_rect, IntPtr.Zero); IntPtr hrgn = XplatUIWin32.Win32CreateRectRgn (excludedArea.Left, excludedArea.Top, excludedArea.Right, excludedArea.Bottom); XplatUIWin32.Win32ExtSelectClipRgn (hdc, hrgn, (int)ClipCombineMode.RGN_OR); XplatUIWin32.Win32DeleteObject (hrgn); dc.ReleaseHdc (); } #endregion } }