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();
}
}
}