using System; using System.ComponentModel; using System.Drawing; using System.Windows.Forms; using Vanara.Extensions; using Vanara.PInvoke; using static Vanara.PInvoke.User32; using static Vanara.PInvoke.UxTheme; namespace Vanara.Windows.Forms { /// A Label containing some text that will be drawn with glowing border on top of the Glass Sheet effect. //[Designer("AeroWizard.Design.ThemedLabelDesigner")] [DefaultProperty("Text")] [ToolboxItem(true), ToolboxBitmap(typeof(ThemedLabel), "ThemedLabel.bmp")] public class ThemedLabel : Label { private const string defaultClass = "TextStyle"; private const int defaultPart = 4; private const int defaultState = 0; private string styleClass; private int stylePart; private int styleState; private bool supportGlass; private TextImageRelation textImageRelation; private VisualTheme theme; /// Initializes a new instance of the class. public ThemedLabel() { SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint | ControlStyles.OptimizedDoubleBuffer | ControlStyles.ResizeRedraw, true); SetStyle(ControlStyles.SupportsTransparentBackColor, true); base.BackColor = Color.Transparent; SetTheme(defaultClass, defaultPart, defaultState); } /// Gets or sets the background color for the control. /// /// /// A that represents the background color of the control. The default is the value of the property. /// [DefaultValue(typeof(Color), "Transparent")] public override Color BackColor { get => base.BackColor; set => base.BackColor = value; } /// Gets or sets a value indicating whether the text has a glow. /// if text has glow; otherwise, . [DefaultValue(false), Category("Appearance")] public bool GlowingText { get; set; } /// Gets or sets the image that is displayed on a . /// /// /// An displayed on the . The default is null. /// [DefaultValue((Image)null)] public new Image Image { get => base.Image; set { base.Image = value; ImageIndex = -1; ImageList = null; } } /// Gets or sets the style class. /// The style class. [DefaultValue(defaultClass), Category("Appearance")] public string StyleClass { get => styleClass; set { if (styleClass != value) { styleClass = value; ResetTheme(); } } } /// Gets or sets the style part. /// The style part. [DefaultValue(defaultPart), Category("Appearance")] public int StylePart { get => stylePart; set { if (stylePart != value) { stylePart = value; Invalidate(); } } } /// Gets or sets the style part. /// The style part. [DefaultValue(defaultState), Category("Appearance")] public int StyleState { get => styleState; set { if (styleState != value) { styleState = value; Invalidate(); } } } /// Gets or sets a value indicating whether this table supports glass (can be enclosed in the glass margin). /// true if supports glass; otherwise, false. [DefaultValue(false), Category("Appearance")] public bool SupportGlass { get => supportGlass; set { if (supportGlass != value) { supportGlass = value; Invalidate(); } } } /// Gets or sets the text image relation. /// The text image relation. [DefaultValue(0), Category("Appearance")] public TextImageRelation TextImageRelation { get => textImageRelation; set { textImageRelation = value; Invalidate(); } } private bool ThemingSupported => Application.RenderWithVisualStyles || DesktopWindowManager.CompositionEnabled; /// Retrieves the size of a rectangular area into which a control can be fitted. /// The custom-sized area for a control. /// An ordered pair of type representing the width and height of a rectangle. public override Size GetPreferredSize(Size proposedSize) { if (Text.Length <= 0 || theme == null) return base.GetPreferredSize(proposedSize); using (var g = CreateGraphics()) { var tff = this.BuildTextFormatFlags(); GraphicsExtension.CalcImageAndTextBounds(new Rectangle(Point.Empty, proposedSize), Text, Font, Image, TextAlign, ImageAlign, TextImageRelation, !AutoSize, 0, ref tff, out var tRect, out var iRect); return Size.Add(Rectangle.Union(tRect, iRect).Size, Padding.Size); } } /// Sets the theme using theme class information. /// Name of the theme class. /// The theme part. /// The theme state. public void SetTheme(string className, int part, int state) { styleClass = className; stylePart = part; styleState = state; ResetTheme(); } /// Sets the theme using information. /// The visual style. public void SetTheme(System.Windows.Forms.VisualStyles.VisualStyleElement visualStyle) => SetTheme(visualStyle?.ClassName, visualStyle?.Part ?? 0, visualStyle?.State ?? 0); internal static Rectangle DeflateRect(Rectangle rect, Padding padding) { rect.X += padding.Left; rect.Y += padding.Top; rect.Width -= padding.Horizontal; rect.Height -= padding.Vertical; return rect; } /// Raises the Paint event. /// A that contains the event data. protected override void OnPaint(PaintEventArgs e) { base.OnPaint(e); if (!Visible) return; try { // Setup variables var r = DeflateRect(ClientRectangle, Padding); var tff = this.BuildTextFormatFlags(); GraphicsExtension.CalcImageAndTextBounds(r, Text, Font, Image, TextAlign, ImageAlign, TextImageRelation, !AutoSize, 0, ref tff, out var tRect, out var iRect); // Draw background if (SupportGlass && !this.IsDesignMode() && ThemingSupported) e.Graphics.Clear(Color.Black); else { if (theme != null && ThemingSupported) theme.DrawBackground(e.Graphics, stylePart, styleState, ClientRectangle, e.ClipRectangle); else e.Graphics.Clear(BackColor); } // Draw image if (Image != null) { e.Graphics.DrawImage(Image, iRect); } // Draw text if (Text.Length > 0) { var rtl = this.GetRightToLeftProperty(); if (theme != null && ThemingSupported) { if (rtl == RightToLeft.Yes) tff |= TextFormatFlags.RightToLeft; if (GlowingText) e.Graphics.DrawViaDIB(tRect, (hdc, rc) => theme.DrawText(Graphics.FromHdc(hdc.DangerousGetHandle()), stylePart, styleState, r, Text, tff, new DTTOPTS(null) { GlowSize = 10, AntiAliasedAlpha = true })); else theme.DrawText(e.Graphics, stylePart, styleState, tRect, Text, tff, !Enabled); } else { var br = ThemingSupported ? SystemBrushes.ActiveCaptionText : SystemBrushes.ControlText; var sf = new StringFormat(StringFormat.GenericDefault); if (rtl == RightToLeft.Yes) sf.FormatFlags |= StringFormatFlags.DirectionRightToLeft; e.Graphics.DrawString(Text, Font, br, ClientRectangle, sf); } } } catch { } } /// Processes Windows messages. /// The Windows to process. protected override void WndProc(ref Message m) { if (!DesignMode && SupportGlass && m.Msg == (int)WindowMessage.WM_NCHITTEST) { m.Result = (IntPtr)HitTestValues.HTTRANSPARENT; return; } base.WndProc(ref m); } private void ResetTheme() { if (styleClass != null && ThemingSupported) { try { theme = new VisualTheme(Parent, styleClass, SupportGlass ? OpenThemeDataOptions.OTD_NONCLIENT : OpenThemeDataOptions.None); } catch { theme = null; } } else theme = null; Refresh(); } } }