// COPYRIGHT (C) Tom. ALL RIGHTS RESERVED. // THE AntdUI PROJECT IS AN WINFORM LIBRARY LICENSED UNDER THE Apache-2.0 License. // LICENSED UNDER THE Apache License, VERSION 2.0 (THE "License") // YOU MAY NOT USE THIS FILE EXCEPT IN COMPLIANCE WITH THE License. // YOU MAY OBTAIN A COPY OF THE LICENSE AT // // http://www.apache.org/licenses/LICENSE-2.0 // // UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING, SOFTWARE // DISTRIBUTED UNDER THE LICENSE IS DISTRIBUTED ON AN "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. // SEE THE LICENSE FOR THE SPECIFIC LANGUAGE GOVERNING PERMISSIONS AND // LIMITATIONS UNDER THE License. // GITEE: https://gitee.com/antdui/AntdUI // GITHUB: https://github.com/AntdUI/AntdUI // CSDN: https://blog.csdn.net/v_132 // QQ: 17379620 using System; using System.ComponentModel; using System.Drawing; using System.Drawing.Design; using System.Windows.Forms; namespace AntdUI { /// /// Label 文本 /// /// 显示一段文本。 [Description("Label 文本")] [ToolboxItem(true)] [DefaultProperty("Text")] public class Label : IControl, ShadowConfig { #region 属性 Color? fore; /// /// 文字颜色 /// [Description("文字颜色"), Category("外观"), DefaultValue(null)] [Editor(typeof(Design.ColorEditor), typeof(UITypeEditor))] public new Color? ForeColor { get => fore; set { if (fore == value) fore = value; fore = value; Invalidate(); } } #region 文本 internal string? text = null; /// /// 文本 /// [Editor(typeof(System.ComponentModel.Design.MultilineStringEditor), typeof(UITypeEditor))] [Description("文本"), Category("外观"), DefaultValue(null)] public override string? Text { get => text; set { if (text == value) return; text = value; if (BeforeAutoSize()) Invalidate(); OnTextChanged(EventArgs.Empty); } } StringFormat stringCNoWrap = new StringFormat { LineAlignment = StringAlignment.Center, Alignment = StringAlignment.Center, FormatFlags = StringFormatFlags.NoWrap }, stringFormat = new StringFormat { LineAlignment = StringAlignment.Center, Alignment = StringAlignment.Near }; ContentAlignment textAlign = ContentAlignment.MiddleLeft; /// /// 文本位置 /// [Description("文本位置"), Category("外观"), DefaultValue(ContentAlignment.MiddleLeft)] public ContentAlignment TextAlign { get => textAlign; set { if (textAlign == value) return; textAlign = value; textAlign.SetAlignment(ref stringFormat); Invalidate(); } } bool autoEllipsis = false; /// /// 文本超出自动处理 /// [Description("文本超出自动处理"), Category("行为"), DefaultValue(false)] public bool AutoEllipsis { get => autoEllipsis; set { if (autoEllipsis == value) return; autoEllipsis = value; stringFormat.Trimming = value ? StringTrimming.EllipsisCharacter : StringTrimming.None; Invalidate(); } } bool textMultiLine = true; /// /// 是否多行 /// [Description("是否多行"), Category("行为"), DefaultValue(true)] public bool TextMultiLine { get => textMultiLine; set { if (textMultiLine == value) return; textMultiLine = value; stringFormat.FormatFlags = value ? 0 : StringFormatFlags.NoWrap; Invalidate(); } } float iconratio = .7F; /// /// 图标比例 /// [Description("图标比例"), Category("外观"), DefaultValue(.7F)] public float IconRatio { get => iconratio; set { if (iconratio == value) return; iconratio = value; IOnSizeChanged(); Invalidate(); } } string? prefix = null; /// /// 前缀 /// [Description("前缀"), Category("外观"), DefaultValue(null)] public string? Prefix { get => prefix; set { if (prefix == value) return; prefix = value; IOnSizeChanged(); if (BeforeAutoSize()) Invalidate(); } } string? prefixSvg = null; /// /// 前缀SVG /// [Description("前缀SVG"), Category("外观"), DefaultValue(null)] public string? PrefixSvg { get => prefixSvg; set { if (prefixSvg == value) return; prefixSvg = value; IOnSizeChanged(); if (BeforeAutoSize()) Invalidate(); } } /// /// 前缀颜色 /// [Description("前缀颜色"), Category("外观"), DefaultValue(null)] [Editor(typeof(Design.ColorEditor), typeof(UITypeEditor))] public Color? PrefixColor { get; set; } /// /// 是否包含前缀 /// public bool HasPrefix { get => prefixSvg != null || prefix != null; } string? suffix = null; /// /// 后缀 /// [Description("后缀"), Category("外观"), DefaultValue(null)] public string? Suffix { get => suffix; set { if (suffix == value) return; suffix = value; IOnSizeChanged(); if (BeforeAutoSize()) Invalidate(); } } string? suffixSvg = null; /// /// 后缀SVG /// [Description("后缀SVG"), Category("外观"), DefaultValue(null)] public string? SuffixSvg { get => suffixSvg; set { if (suffixSvg == value) return; suffixSvg = value; IOnSizeChanged(); if (BeforeAutoSize()) Invalidate(); } } /// /// 后缀颜色 /// [Description("后缀颜色"), Category("外观"), DefaultValue(null)] [Editor(typeof(Design.ColorEditor), typeof(UITypeEditor))] public Color? SuffixColor { get; set; } /// /// 缀标完全展示 /// [Description("缀标完全展示"), Category("外观"), DefaultValue(true)] public bool Highlight { get; set; } = true; /// /// 是否包含后缀 /// public bool HasSuffix { get => suffixSvg != null || suffix != null; } /// /// 超出文字显示 Tooltip /// [Description("超出文字显示 Tooltip"), Category("外观"), DefaultValue(true)] public bool ShowTooltip { get; set; } = true; /// /// 超出文字提示配置 /// [Browsable(false)] public TooltipConfig? TooltipConfig { get; set; } #endregion #region 阴影 int shadow = 0; [Description("阴影大小"), Category("阴影"), DefaultValue(0)] public int Shadow { get => shadow; set { if (shadow == value) return; shadow = value; Invalidate(); } } [Description("阴影颜色"), Category("阴影"), DefaultValue(null)] [Editor(typeof(Design.ColorEditor), typeof(UITypeEditor))] public Color? ShadowColor { get; set; } float shadowOpacity = 0.3F; [Description("阴影透明度"), Category("阴影"), DefaultValue(0.3F)] public float ShadowOpacity { get => shadowOpacity; set { if (shadowOpacity == value) return; if (value < 0) value = 0; else if (value > 1) value = 1; shadowOpacity = value; Invalidate(); } } int shadowOffsetX = 0; [Description("阴影偏移X"), Category("阴影"), DefaultValue(0)] public int ShadowOffsetX { get => shadowOffsetX; set { if (shadowOffsetX == value) return; shadowOffsetX = value; Invalidate(); } } int shadowOffsetY = 0; [Description("阴影偏移Y"), Category("阴影"), DefaultValue(0)] public int ShadowOffsetY { get => shadowOffsetY; set { if (shadowOffsetY == value) return; shadowOffsetY = value; Invalidate(); } } #endregion #endregion #region 渲染 protected override void OnPaint(PaintEventArgs e) { var g = e.Graphics.High(); var rect_read = ReadRectangle; Color _fore = Style.Db.DefaultColor; if (fore.HasValue) _fore = fore.Value; PaintText(g, text, _fore, rect_read); if (shadow > 0) { using (var bmp = new Bitmap(Width, Height)) { using (var g2 = Graphics.FromImage(bmp)) { PaintText(g2, text, ShadowColor ?? _fore, rect_read); } Helper.Blur(bmp, shadow); g.DrawImage(bmp, new Rectangle(shadowOffsetX, shadowOffsetY, bmp.Width, bmp.Height), shadowOpacity); } } this.PaintBadge(g); base.OnPaint(e); } #region 渲染帮助 bool ellipsis = false; void PaintText(Graphics g, string? text, Color color, Rectangle rect_read) { if (!string.IsNullOrEmpty(text)) { Rectangle rec; var font_size = g.MeasureString(text, Font).Size(); bool has_prefixText = prefix != null, has_suffixText = suffix != null, has_prefix = prefixSvg != null, has_suffix = suffixSvg != null; if (has_prefixText || has_suffixText || has_prefix || has_suffix) { switch (textAlign) { case ContentAlignment.TopLeft: case ContentAlignment.MiddleLeft: case ContentAlignment.BottomLeft: rec = PaintTextLeft(g, color, rect_read, font_size, has_prefixText, has_suffixText, has_prefix, has_suffix); break; case ContentAlignment.TopRight: case ContentAlignment.MiddleRight: case ContentAlignment.BottomRight: rec = PaintTextRight(g, color, rect_read, font_size, has_prefixText, has_suffixText, has_prefix, has_suffix); break; default: rec = PaintTextCenter(g, color, rect_read, font_size, has_prefixText, has_suffixText, has_prefix, has_suffix); break; } } else rec = rect_read; if (autoEllipsis) ellipsis = rec.Width < font_size.Width; else ellipsis = false; using (var brush = new SolidBrush(color)) { g.DrawStr(text, Font, brush, rec, stringFormat); } } } Rectangle PaintTextLeft(Graphics g, Color color, Rectangle rect_read, Size font_size, bool has_prefixText, bool has_suffixText, bool has_prefix, bool has_suffix) { int hx = 0; if (has_prefixText) { var font_size_prefix = g.MeasureString(prefix, Font).Size(); int x = rect_read.X - font_size_prefix.Width, w = font_size_prefix.Width; var rect_l = RecFixAuto(x, w, rect_read, font_size); if (Highlight) { hx = font_size_prefix.Width; rect_l.X = 0; } using (var brush = new SolidBrush(PrefixColor ?? color)) { g.DrawStr(prefix, Font, brush, rect_l, stringCNoWrap); } } else if (has_prefix) { int icon_size = (int)(font_size.Height * iconratio); int x = rect_read.X - icon_size, w = icon_size; var rect_l = RecFixAuto(x, w, rect_read, font_size); if (Highlight) { hx = icon_size; rect_l.X = 0; } g.GetImgExtend(prefixSvg, rect_l, PrefixColor ?? color); } if (has_suffixText) { var font_size_suffix = g.MeasureString(suffix, Font).Size(); int x = rect_read.X + hx + font_size.Width, w = font_size_suffix.Width; using (var brush = new SolidBrush(SuffixColor ?? color)) { g.DrawStr(suffix, Font, brush, RecFixAuto(x, w, rect_read, font_size), stringCNoWrap); } } else if (has_suffix) { int icon_size = (int)(font_size.Height * iconratio); int x = rect_read.X + hx + font_size.Width, w = icon_size; var rect_r = RecFixAuto(x, w, rect_read, font_size); using (var _bmp = SvgExtend.GetImgExtend(suffixSvg, rect_r, SuffixColor ?? color)) { if (_bmp != null) g.DrawImage(_bmp, rect_r); } } if (hx > 0) return new Rectangle(rect_read.X + hx, rect_read.Y, rect_read.Width - hx, rect_read.Height); return rect_read; } Rectangle PaintTextRight(Graphics g, Color color, Rectangle rect_read, Size font_size, bool has_prefixText, bool has_suffixText, bool has_prefix, bool has_suffix) { int hr = 0; if (has_suffixText) { var font_size_suffix = g.MeasureString(suffix, Font).Size(); int x = rect_read.Right, w = font_size_suffix.Width; var rect_l = RecFixAuto(x, w, rect_read, font_size); if (Highlight) { hr = font_size_suffix.Width; rect_l.X = rect_read.Right - hr; } using (var brush = new SolidBrush(SuffixColor ?? color)) { g.DrawStr(suffix, Font, brush, rect_l, stringCNoWrap); } } else if (has_suffix) { int icon_size = (int)(font_size.Height * iconratio); int x = rect_read.Right, w = icon_size; var rect_r = RecFixAuto(x, w, rect_read, font_size); if (Highlight) { hr = icon_size; rect_r.X = rect_read.Right - icon_size; } g.GetImgExtend(suffixSvg, rect_r, SuffixColor ?? color); } if (has_prefixText) { var font_size_prefix = g.MeasureString(prefix, Font).Size(); int x = rect_read.Right - hr - font_size.Width - font_size_prefix.Width, w = font_size_prefix.Width; var rect_l = RecFixAuto(x, w, rect_read, font_size); using (var brush = new SolidBrush(PrefixColor ?? color)) { g.DrawStr(prefix, Font, brush, rect_l, stringCNoWrap); } } else if (has_prefix) { int icon_size = (int)(font_size.Height * iconratio); int x = rect_read.Right - hr - font_size.Width - icon_size, w = icon_size; var rect_l = RecFixAuto(x, w, rect_read, font_size); g.GetImgExtend(prefixSvg, rect_l, PrefixColor ?? color); } if (hr > 0) return new Rectangle(rect_read.X, rect_read.Y, rect_read.Width - hr, rect_read.Height); return rect_read; } Rectangle PaintTextCenter(Graphics g, Color color, Rectangle rect_read, Size font_size, bool has_prefixText, bool has_suffixText, bool has_prefix, bool has_suffix) { int cex = rect_read.X + (rect_read.Width - font_size.Width) / 2; if (has_prefixText) { var font_size_prefix = g.MeasureString(prefix, Font).Size(); var rect_l = RecFixAuto(cex - font_size_prefix.Width, font_size_prefix.Width, rect_read, font_size); using (var brush = new SolidBrush(PrefixColor ?? color)) { g.DrawStr(prefix, Font, brush, rect_l, stringCNoWrap); } } else if (has_prefix) { int icon_size = (int)(font_size.Height * iconratio); var rect_l = RecFixAuto(cex - icon_size, icon_size, rect_read, font_size); g.GetImgExtend(prefixSvg, rect_l, PrefixColor ?? color); } if (has_suffixText) { var font_size_suffix = g.MeasureString(suffix, Font).Size(); using (var brush = new SolidBrush(SuffixColor ?? color)) { g.DrawStr(suffix, Font, brush, RecFixAuto(cex + font_size.Width, font_size_suffix.Width, rect_read, font_size), stringCNoWrap); } } else if (has_suffix) { int icon_size = (int)(font_size.Height * iconratio); var rect_r = RecFixAuto(cex + font_size.Width, icon_size, rect_read, font_size); g.GetImgExtend(suffixSvg, rect_r, SuffixColor ?? color); } return rect_read; } Rectangle RecFixAuto(int x, int w, Rectangle rect_read, Size font_size) { switch (textAlign) { case ContentAlignment.TopLeft: case ContentAlignment.TopRight: case ContentAlignment.TopCenter: return RecFixT(x, w, rect_read, font_size); case ContentAlignment.BottomLeft: case ContentAlignment.BottomCenter: case ContentAlignment.BottomRight: return RecFixB(x, w, rect_read, font_size); default: return RecFix(x, w, rect_read); } } Rectangle RecFix(int x, int w, Rectangle rect_read) { return new Rectangle(x, rect_read.Y, w, rect_read.Height); } Rectangle RecFixT(int x, int w, Rectangle rect_read, Size font_size) { return new Rectangle(x, rect_read.Y, w, font_size.Height); } Rectangle RecFixB(int x, int w, Rectangle rect_read, Size font_size) { return new Rectangle(x, rect_read.Bottom - font_size.Height, w, font_size.Height); } #endregion TooltipForm? tooltipForm = null; protected override void OnMouseHover(EventArgs e) { tooltipForm?.Close(); tooltipForm = null; if (ellipsis && ShowTooltip && text != null) { if (tooltipForm == null) { tooltipForm = new TooltipForm(this, text, TooltipConfig ?? new TooltipConfig { Font = Font, ArrowAlign = TAlign.Top, }); tooltipForm.Show(this); } } base.OnMouseHover(e); } public override Rectangle ReadRectangle { get => ClientRectangle.PaddingRect(Padding); } #endregion #region 自动大小 /// /// 自动大小 /// [Browsable(true)] [Description("自动大小"), Category("外观"), DefaultValue(false)] public override bool AutoSize { get => base.AutoSize; set { if (base.AutoSize == value) return; base.AutoSize = value; if (value) { if (autoSize == TAutoSize.None) autoSize = TAutoSize.Auto; } else autoSize = TAutoSize.None; BeforeAutoSize(); } } TAutoSize autoSize = TAutoSize.None; /// /// 自动大小模式 /// [Description("自动大小模式"), Category("外观"), DefaultValue(TAutoSize.None)] public TAutoSize AutoSizeMode { get => autoSize; set { if (autoSize == value) return; autoSize = value; base.AutoSize = autoSize != TAutoSize.None; BeforeAutoSize(); } } protected override void OnFontChanged(EventArgs e) { BeforeAutoSize(); base.OnFontChanged(e); } public override Size GetPreferredSize(Size proposedSize) { if (autoSize == TAutoSize.None) return base.GetPreferredSize(proposedSize); else if (autoSize == TAutoSize.Width) return new Size(PSize.Width, base.GetPreferredSize(proposedSize).Height); else if (autoSize == TAutoSize.Height) return new Size(base.GetPreferredSize(proposedSize).Width, PSize.Height); return PSize; } internal Size PSize { get { bool has_prefixText = prefix != null, has_suffixText = suffix != null, has_prefix = prefixSvg != null, has_suffix = suffixSvg != null; return Helper.GDI(g => { var font_size = g.MeasureString(text ?? Config.NullText, Font); if (has_prefixText || has_suffixText || has_prefix || has_suffix) { float add = 0; if (has_prefix) add += font_size.Height; else if (has_prefixText) { var font_size_prefix = g.MeasureString(prefix, Font).Size().Width; add += font_size_prefix; } if (has_suffix) add += font_size.Height; else if (has_suffixText) { var font_size_suffix = g.MeasureString(suffix, Font).Size().Width; add += font_size_suffix; } return new Size((int)Math.Ceiling(font_size.Width + add), (int)Math.Ceiling(font_size.Height)); } else return font_size.Size(); }); } } protected override void OnResize(EventArgs e) { BeforeAutoSize(); base.OnResize(e); } internal bool BeforeAutoSize() { if (autoSize == TAutoSize.None) return true; if (InvokeRequired) { bool flag = false; Invoke(new Action(() => { flag = BeforeAutoSize(); })); return flag; } var PS = PSize; switch (autoSize) { case TAutoSize.Width: if (Width == PS.Width) return true; Width = PS.Width; break; case TAutoSize.Height: if (Height == PS.Height) return true; Height = PS.Height; break; case TAutoSize.Auto: default: if (Width == PS.Width && Height == PS.Height) return true; Size = PS; break; } return false; } #endregion } }