// 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.Drawing.Drawing2D;
using System.Windows.Forms;
namespace AntdUI
{
///
/// Tag 标签
///
/// 进行标记和分类的小标签。
[Description("Tag 标签")]
[ToolboxItem(true)]
[DefaultProperty("Text")]
public class Tag : IControl
{
#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 背景
Color? back;
///
/// 背景颜色
///
[Description("背景颜色"), Category("外观"), DefaultValue(null)]
[Editor(typeof(Design.ColorEditor), typeof(UITypeEditor))]
public new Color? BackColor
{
get => back;
set
{
if (back == value) return;
back = value;
Invalidate();
}
}
Image? backImage = null;
///
/// 背景图片
///
[Description("背景图片"), Category("外观"), DefaultValue(null)]
public new Image? BackgroundImage
{
get => backImage;
set
{
if (backImage == value) return;
backImage = value;
Invalidate();
}
}
TFit backFit = TFit.Fill;
///
/// 背景图片布局
///
[Description("背景图片布局"), Category("外观"), DefaultValue(TFit.Fill)]
public new TFit BackgroundImageLayout
{
get => backFit;
set
{
if (backFit == value) return;
backFit = value;
Invalidate();
}
}
#endregion
#region 边框
internal float borderWidth = 1;
///
/// 边框宽度
///
[Description("边框宽度"), Category("边框"), DefaultValue(1F)]
public float BorderWidth
{
get => borderWidth;
set
{
if (borderWidth == value) return;
borderWidth = value;
Invalidate();
}
}
#endregion
internal int radius = 6;
///
/// 圆角
///
[Description("圆角"), Category("外观"), DefaultValue(6)]
public int Radius
{
get => radius;
set
{
if (radius == value) return;
radius = value;
if (BeforeAutoSize()) Invalidate();
}
}
internal TTypeMini type = TTypeMini.Default;
///
/// 类型
///
[Description("类型"), Category("外观"), DefaultValue(TTypeMini.Default)]
public TTypeMini Type
{
get => type;
set
{
if (type == value) return;
type = value;
Invalidate();
}
}
bool closeIcon = false;
///
/// 是否显示关闭图标
///
[Description("是否显示关闭图标"), Category("行为"), DefaultValue(false)]
public bool CloseIcon
{
get => closeIcon;
set
{
if (closeIcon == value) return;
closeIcon = value;
if (BeforeAutoSize()) 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 stringFormat = Helper.SF_NoWrap();
ContentAlignment textAlign = ContentAlignment.MiddleCenter;
///
/// 文本位置
///
[Description("文本位置"), Category("外观"), DefaultValue(ContentAlignment.MiddleCenter)]
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;
}
}
bool textMultiLine = false;
///
/// 是否多行
///
[Description("是否多行"), Category("行为"), DefaultValue(false)]
public bool TextMultiLine
{
get => textMultiLine;
set
{
if (textMultiLine == value) return;
textMultiLine = value;
stringFormat.FormatFlags = value ? 0 : StringFormatFlags.NoWrap;
Invalidate();
}
}
#endregion
#region 图片
Image? image = null;
///
/// 图像
///
[Description("图像"), Category("外观"), DefaultValue(null)]
public Image? Image
{
get => image;
set
{
if (image == value) return;
image = value;
if (BeforeAutoSize()) Invalidate();
}
}
string? imageSvg = null;
[Description("图像SVG"), Category("外观"), DefaultValue(null)]
public string? ImageSvg
{
get => imageSvg;
set
{
if (imageSvg == value) return;
imageSvg = value;
if (BeforeAutoSize()) Invalidate();
}
}
///
/// 是否包含图片
///
public bool HasImage
{
get => imageSvg != null || image != null;
}
///
/// 图像大小
///
[Description("图像大小"), Category("外观"), DefaultValue(typeof(Size), "0, 0")]
public Size ImageSize { get; set; } = new Size(0, 0);
#endregion
#endregion
#region 事件
///
/// Close时发生
///
[Description("Close时发生"), Category("行为")]
public event RBoolEventHandler? CloseChanged = null;
#endregion
#region 渲染
protected override void OnPaint(PaintEventArgs e)
{
var g = e.Graphics.High();
var rect_read = ReadRectangle;
if (backImage != null) g.PaintImg(rect_read, backImage, backFit, radius, false);
float _radius = radius * Config.Dpi;
Color _fore, _back, _bor;
switch (type)
{
case TTypeMini.Default:
_back = Style.Db.TagDefaultBg;
_fore = Style.Db.TagDefaultColor;
_bor = Style.Db.DefaultBorder;
break;
case TTypeMini.Error:
_back = Style.Db.ErrorBg;
_fore = Style.Db.Error;
_bor = Style.Db.ErrorBorder;
break;
case TTypeMini.Success:
_back = Style.Db.SuccessBg;
_fore = Style.Db.Success;
_bor = Style.Db.SuccessBorder;
break;
case TTypeMini.Info:
_back = Style.Db.InfoBg;
_fore = Style.Db.Info;
_bor = Style.Db.InfoBorder;
break;
case TTypeMini.Warn:
_back = Style.Db.WarningBg;
_fore = Style.Db.Warning;
_bor = Style.Db.WarningBorder;
break;
case TTypeMini.Primary:
default:
_back = Style.Db.PrimaryBg;
_fore = Style.Db.Primary;
_bor = Style.Db.Primary;
break;
}
if (fore.HasValue) _fore = fore.Value;
if (back.HasValue) _back = back.Value;
if (backImage != null) g.PaintImg(rect_read, backImage, backFit, _radius, false);
using (var path = rect_read.RoundPath(_radius))
{
#region 绘制背景
using (var brush = new SolidBrush(_back))
{
g.FillPath(brush, path);
}
if (borderWidth > 0)
{
float border = borderWidth * Config.Dpi;
using (var brush = new Pen(_bor, border))
{
g.DrawPath(brush, path);
}
}
#endregion
PaintText(g, text, _fore, rect_read);
}
this.PaintBadge(g);
base.OnPaint(e);
}
#region 渲染帮助
internal void PaintText(Graphics g, string? text, Color color, Rectangle rect_read)
{
var font_size = g.MeasureString(text ?? Config.NullText, Font).Size();
if (text == null)
{
if (PaintImageNoText(g, color, font_size, rect_read))
{
if (closeIcon)
{
int size = (int)(rect_read.Height * .4F);
var rect_arrow = new Rectangle(rect_read.X + (rect_read.Width - size) / 2, rect_read.Y + (rect_read.Height - size) / 2, size, size);
rect_close = rect_arrow;
if (hover_close.Animation) g.PaintIconClose(rect_arrow, Helper.ToColor(hover_close.Value + Style.Db.TextQuaternary.A, Style.Db.Text));
else if (hover_close.Switch) g.PaintIconClose(rect_arrow, Style.Db.Text);
else g.PaintIconClose(rect_arrow, Style.Db.TextQuaternary);
}
}
}
else
{
bool right = RightToLeft == RightToLeft.Yes;
var rect = ReadRectangle.IconRect(font_size.Height, HasImage, closeIcon, right, false);
rect_close = rect.r;
if (closeIcon)
{
if (hover_close.Animation) g.PaintIconClose(rect.r, Helper.ToColor(hover_close.Value + Style.Db.TextQuaternary.A, Style.Db.Text), .8F);
else if (hover_close.Switch) g.PaintIconClose(rect.r, Style.Db.Text, .8F);
else g.PaintIconClose(rect.r, Style.Db.TextQuaternary, .8F);
}
PaintImage(g, color, rect.l);
using (var brush = new SolidBrush(color))
{
g.DrawStr(text, Font, brush, rect.text, stringFormat);
}
}
}
///
/// 渲染图片(没有文字)
///
/// GDI
/// 颜色
/// 字体大小
/// 客户区域
bool PaintImageNoText(Graphics g, Color? color, Size font_size, Rectangle rect_read)
{
if (imageSvg != null)
{
g.GetImgExtend(imageSvg, GetImageRectCenter(font_size, rect_read), color);
return false;
}
else if (image != null)
{
g.DrawImage(image, GetImageRectCenter(font_size, rect_read));
return false;
}
return true;
}
///
/// 居中的图片绘制区域
///
/// 字体大小
/// 客户区域
Rectangle GetImageRectCenter(Size font_size, Rectangle rect_read)
{
if (ImageSize.Width > 0 && ImageSize.Height > 0)
{
int w = (int)(ImageSize.Width * Config.Dpi), h = (int)(ImageSize.Height * Config.Dpi);
return new Rectangle(rect_read.X + (rect_read.Width - w) / 2, rect_read.Y + (rect_read.Height - h) / 2, w, h);
}
else
{
int w = (int)(font_size.Height * 0.8F);
return new Rectangle(rect_read.X + (rect_read.Width - w) / 2, rect_read.Y + (rect_read.Height - w) / 2, w, w);
}
}
///
/// 渲染图片
///
/// GDI
/// 颜色
/// 图标区域
void PaintImage(Graphics g, Color? color, Rectangle rectl)
{
if (imageSvg != null) g.GetImgExtend(imageSvg, GetImageRect(rectl), color);
else if (image != null) g.DrawImage(image, GetImageRect(rectl));
}
///
/// 图片绘制区域
///
/// 图标区域
Rectangle GetImageRect(Rectangle rectl)
{
if (ImageSize.Width > 0 && ImageSize.Height > 0)
{
int w = (int)(ImageSize.Width * Config.Dpi), h = (int)(ImageSize.Height * Config.Dpi);
return new Rectangle(rectl.X + (rectl.Width - w) / 2, rectl.Y + (rectl.Height - h) / 2, w, h);
}
else return rectl;
}
#endregion
public override Rectangle ReadRectangle
{
get => ClientRectangle.PaddingRect(Padding, borderWidth * Config.Dpi);
}
public override GraphicsPath RenderRegion
{
get
{
var rect_read = ReadRectangle;
float _radius = radius * Config.Dpi;
return rect_read.RoundPath(_radius);
}
}
#endregion
#region 鼠标
ITaskOpacity hover_close;
public Tag()
{
base.BackColor = Color.Transparent;
hover_close = new ITaskOpacity(this);
}
RectangleF rect_close;
protected override void OnMouseClick(MouseEventArgs e)
{
if (e.Button == MouseButtons.Left && closeIcon && rect_close.Contains(e.Location))
{
bool isclose = false;
if (CloseChanged == null || CloseChanged(this, EventArgs.Empty)) isclose = true;
if (isclose) Dispose();
return;
}
base.OnMouseClick(e);
}
protected override void OnMouseMove(MouseEventArgs e)
{
if (closeIcon)
{
hover_close.MaxValue = Style.Db.Text.A - Style.Db.TextQuaternary.A;
hover_close.Switch = rect_close.Contains(e.Location);
SetCursor(hover_close.Switch);
}
else SetCursor(false);
base.OnMouseMove(e);
}
#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
{
return Helper.GDI(g =>
{
var font_size = g.MeasureString(text ?? Config.NullText, Font).Size();
int count = 0;
if (HasImage) count++;
if (closeIcon) count++;
return new Size(font_size.Width + (int)(14F * Config.Dpi) + (font_size.Height * count), font_size.Height + (int)(8F * Config.Dpi));
});
}
}
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
}
}