// 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.Drawing2D; using System.Windows.Forms; namespace AntdUI { /// /// Alert 警告提示 /// /// 警告提示,展现需要关注的信息。 [Description("Alert 警告提示")] [ToolboxItem(true)] [DefaultProperty("Text")] [Designer(typeof(IControlDesigner))] public class Alert : IControl { #region 属性 int radius = 6; /// /// 圆角 /// [Description("圆角"), Category("外观"), DefaultValue(6)] public int Radius { get => radius; set { if (radius == value) return; radius = value; Invalidate(); } } float borWidth = 0F; /// /// 边框宽度 /// [Description("边框宽度"), Category("边框"), DefaultValue(0F)] public float BorderWidth { get => borWidth; set { if (borWidth == value) return; borWidth = value; Invalidate(); } } string? text = null; /// /// 文本 /// [Description("文本"), Category("外观"), DefaultValue(null)] public override string? Text { get => text; set { if (text == value) return; if (loop && string.IsNullOrEmpty(value)) { task?.Dispose(); task = null; } font_size = null; text = value; Invalidate(); OnTextChanged(EventArgs.Empty); } } string? textTitle = null; /// /// 标题 /// [Description("标题"), Category("外观"), DefaultValue(null)] public string? TextTitle { get => textTitle; set { if (textTitle == value) return; textTitle = value; Invalidate(); } } TType icon = TType.None; /// /// 样式 /// [Description("样式"), Category("外观"), DefaultValue(TType.None)] public TType Icon { get => icon; set { if (icon == value) return; icon = value; Invalidate(); } } bool loop = false; /// /// 文本轮播 /// [Description("文本轮播"), Category("外观"), DefaultValue(false)] public bool Loop { get => loop; set { if (loop == value) return; loop = value; if (IsHandleCreated) StartTask(); } } protected override void OnHandleCreated(EventArgs e) { base.OnHandleCreated(e); if (loop) StartTask(); } protected override void OnFontChanged(EventArgs e) { font_size = null; base.OnFontChanged(e); } /// /// 文本轮播速率 /// [Description("文本轮播速率"), Category("外观"), DefaultValue(10)] public int LoopSpeed { get; set; } = 10; #region 动画 ITask? task = null; private void StartTask() { task?.Dispose(); if (loop) { task = new ITask(this, () => { if (font_size.HasValue) { val += 1F; if (val > font_size.Value.Width) { if (Width > font_size.Value.Width) val = 0F; else val = -(Width - Padding.Horizontal); } Invalidate(); } return loop; }, LoopSpeed); } else Invalidate(); } #endregion #region 参数 float val = 0; SizeF? font_size = null; #endregion /// /// 显示区域(容器) /// public override Rectangle DisplayRectangle { get => ClientRectangle.DeflateRect(Padding); } #endregion #region 渲染 protected override void OnPaint(PaintEventArgs e) { var rect = DisplayRectangle; var g = e.Graphics.High(); if (icon == TType.None) { if (loop) { if (font_size == null && !string.IsNullOrEmpty(text)) font_size = g.MeasureString(text, Font); if (font_size.HasValue) { g.SetClip(rect); PaintText(g, rect, font_size.Value, ForeColor); g.ResetClip(); } } else { if (string.IsNullOrEmpty(textTitle)) { var size = g.MeasureString(text, Font); font_size = size; float icon_size = size.Height * 0.86F, gap = icon_size * 0.4F; using (var brush = new SolidBrush(ForeColor)) { var rect_txt = new RectangleF(rect.X + gap, rect.Y, rect.Width - gap * 2, rect.Height); g.DrawStr(text, Font, brush, rect_txt, stringLeft); } } else { using (var font_title = new Font(Font.FontFamily, Font.Size * 1.14F, Font.Style)) { var size_title = g.MeasureString(textTitle, font_title); float icon_size = size_title.Height * 1.2F, gap = icon_size * 0.5F; using (var brush = new SolidBrush(ForeColor)) { var rect_txt = new RectangleF(rect.X + gap, rect.Y + gap, rect.Width - (gap * 2), size_title.Height); g.DrawStr(textTitle, font_title, brush, rect_txt, stringLeft); var desc_y = rect_txt.Bottom + icon_size * 0.33F; var rect_txt_desc = new RectangleF(rect_txt.X, desc_y, rect_txt.Width, rect.Height - (desc_y + gap)); g.DrawStr(text, Font, brush, rect_txt_desc, stringLTEllipsis); } } } } } else { float _radius = radius * Config.Dpi; Color back, bor_color, color = Style.Db.Text; switch (icon) { case TType.Success: back = Style.Db.SuccessBg; bor_color = Style.Db.SuccessBorder; break; case TType.Info: back = Style.Db.InfoBg; bor_color = Style.Db.InfoBorder; break; case TType.Warn: back = Style.Db.WarningBg; bor_color = Style.Db.WarningBorder; break; case TType.Error: back = Style.Db.ErrorBg; bor_color = Style.Db.ErrorBorder; break; default: back = Style.Db.SuccessBg; bor_color = Style.Db.SuccessBorder; break; } using (var path = rect.RoundPath(_radius)) { using (var brush = new SolidBrush(back)) { g.FillPath(brush, path); } if (loop) { if (font_size == null && !string.IsNullOrEmpty(text)) font_size = g.MeasureString(text, Font); if (font_size.HasValue) { int icon_size = (int)(font_size.Value.Height * .86F), gap = (int)(icon_size * .4F); var rect_icon = new Rectangle(gap, rect.Y + (rect.Height - icon_size) / 2, icon_size, icon_size); PaintText(g, rect, rect_icon, font_size.Value, color, back, _radius); g.ResetClip(); g.PaintIcons(icon, rect_icon, Style.Db.BgBase); } } else { var size = g.MeasureString(text, Font); font_size = size; if (string.IsNullOrEmpty(textTitle)) { int icon_size = (int)(font_size.Value.Height * .86F), gap = (int)(icon_size * .4F); var rect_icon = new Rectangle(rect.X + gap, rect.Y + (rect.Height - icon_size) / 2, icon_size, icon_size); g.PaintIcons(icon, rect_icon, Style.Db.BgBase); using (var brush = new SolidBrush(color)) { var rect_txt = new RectangleF(rect_icon.X + rect_icon.Width + gap, rect.Y, rect.Width - (rect_icon.Width + gap * 2), rect.Height); g.DrawStr(text, Font, brush, rect_txt, stringLeft); } } else { using (var font_title = new Font(Font.FontFamily, Font.Size * 1.14F, Font.Style)) { var size_title = g.MeasureString(textTitle, font_title); int icon_size = (int)(font_size.Value.Height * 1.2F), gap = (int)(icon_size * .5F); var rect_icon = new Rectangle(rect.X + gap, rect.Y + gap, icon_size, icon_size); g.PaintIcons(icon, rect_icon, Style.Db.BgBase); using (var brush = new SolidBrush(color)) { var rect_txt = new RectangleF(rect_icon.X + rect_icon.Width + icon_size / 2F, rect_icon.Y, rect.Width - (rect_icon.Width + gap * 2), rect_icon.Height); g.DrawStr(textTitle, font_title, brush, rect_txt, stringLeft); var desc_y = rect_txt.Bottom + icon_size * 0.2F; var rect_txt_desc = new RectangleF(rect_txt.X, desc_y, rect_txt.Width, rect.Height - (desc_y + gap)); g.DrawStr(text, Font, brush, rect_txt_desc, stringLTEllipsis); } } } } if (borWidth > 0) { using (var brush_bor = new Pen(bor_color, borWidth * Config.Dpi)) { g.DrawPath(brush_bor, path); } } } } this.PaintBadge(g); base.OnPaint(e); } #region 渲染帮助 readonly StringFormat stringLTEllipsis = Helper.SF_Ellipsis(tb: StringAlignment.Near, lr: StringAlignment.Near); readonly StringFormat stringCenter = Helper.SF_NoWrap(); readonly StringFormat stringLeft = Helper.SF_ALL(lr: StringAlignment.Near); /// /// 渲染文字 /// /// GDI /// 区域 /// 文字大小 /// 文字颜色 void PaintText(Graphics g, RectangleF rect, SizeF size, Color fore) { using (var brush = new SolidBrush(fore)) { if (string.IsNullOrEmpty(textTitle)) { var rect_txt = new RectangleF(rect.X - val, rect.Y, size.Width, rect.Height); g.DrawStr(text, Font, brush, rect_txt, stringCenter); if (rect.Width > size.Width) { var maxw = rect.Width + rect_txt.Width / 2; var rect_txt2 = new RectangleF(rect_txt.Right, rect_txt.Y, rect_txt.Width, rect_txt.Height); while (rect_txt2.X < maxw) { g.DrawStr(text, Font, brush, rect_txt2, stringCenter); rect_txt2.X = rect_txt2.Right; } } } else { var size_title = g.MeasureString(textTitle, Font); var rect_txt = new RectangleF(rect.X + size_title.Width - val, rect.Y, size.Width, rect.Height); g.DrawStr(text, Font, brush, rect_txt, stringCenter); if (rect.Width > size.Width) { var maxw = rect.Width + rect_txt.Width / 2; var rect_txt2 = new RectangleF(rect_txt.Right, rect_txt.Y, rect_txt.Width, rect_txt.Height); while (rect_txt2.X < maxw) { g.DrawStr(text, Font, brush, rect_txt2, stringCenter); rect_txt2.X = rect_txt2.Right; } } var rect_icon_l = new RectangleF(rect.X, rect.Y, (size.Height + size_title.Width) * 2, rect.Height); using (var brush2 = new LinearGradientBrush(rect_icon_l, BackColor, Color.Transparent, 0F)) { g.FillRectangle(brush2, rect_icon_l); g.FillRectangle(brush2, rect_icon_l); } g.DrawStr(TextTitle, Font, brush, new RectangleF(rect.X, rect.Y, size_title.Width, rect.Height), stringCenter); } } } /// /// 渲染文字(渐变遮罩) /// /// GDI /// 区域 /// 文字大小 /// 文字颜色 /// 背景颜色 void PaintText(Graphics g, RectangleF rect, RectangleF rect_icon, SizeF size, Color fore, Color back, float radius) { using (var brush_fore = new SolidBrush(fore)) { var rect_txt = new RectangleF(rect.X - val, rect.Y, size.Width, rect.Height); g.SetClip(new RectangleF(rect.X, rect_txt.Y + ((rect.Height - size.Height) / 2), rect.Width, size.Height)); g.DrawStr(text, Font, brush_fore, rect_txt, stringCenter); if (rect.Width > size.Width) { var maxw = rect.Width + rect_txt.Width / 2; var rect_txt2 = new RectangleF(rect_txt.Right, rect_txt.Y, rect_txt.Width, rect_txt.Height); while (rect_txt2.X < maxw) { g.DrawStr(text, Font, brush_fore, rect_txt2, stringCenter); rect_txt2.X = rect_txt2.Right; } } RectangleF rect_icon_l; if (string.IsNullOrEmpty(textTitle)) { rect_icon_l = new RectangleF(rect.X, rect.Y, size.Height * 2, rect.Height); using (var brush = new LinearGradientBrush(rect_icon_l, back, Color.Transparent, 0F)) { rect_icon_l.Width -= 1F; g.FillRectangle(brush, rect_icon_l); g.FillRectangle(brush, rect_icon_l); } } else { var size_title = g.MeasureString(TextTitle, Font).Size(); rect_icon_l = new RectangleF(rect.X, rect.Y, (size.Height + size_title.Width) * 2, rect.Height); using (var brush = new LinearGradientBrush(rect_icon_l, back, Color.Transparent, 0F)) { g.FillRectangle(brush, rect_icon_l); g.FillRectangle(brush, rect_icon_l); } g.DrawStr(TextTitle, Font, brush_fore, new RectangleF(rect_icon.Right, rect.Y, size_title.Width, rect.Height), stringCenter); } var rect_icon_r = new RectangleF(rect.Right - rect_icon_l.Width, rect_icon_l.Y, rect_icon_l.Width, rect_icon_l.Height); using (var brush = new LinearGradientBrush(rect_icon_r, Color.Transparent, back, 0F)) { rect_icon_r.X += 1F; rect_icon_r.Width -= 1F; g.FillRectangle(brush, rect_icon_r); g.FillRectangle(brush, rect_icon_r); } } } #endregion public override Rectangle ReadRectangle { get => DisplayRectangle; } public override GraphicsPath RenderRegion { get => DisplayRectangle.RoundPath(radius * Config.Dpi); } #endregion #region 事件 protected override void OnMouseEnter(EventArgs e) { task?.Dispose(); base.OnMouseEnter(e); } protected override void OnMouseLeave(EventArgs e) { if (loop) StartTask(); base.OnMouseLeave(e); } #endregion } }