// 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.Drawing.Imaging; using System.Windows.Forms; namespace AntdUI { /// /// Panel 面板 /// /// 内容区域。 [Description("Panel 面板")] [ToolboxItem(true)] [DefaultProperty("Text")] [Designer(typeof(IControlDesigner))] public class Panel : IControl, ShadowConfig, IMessageFilter, IEventListener { #region 属性 int radius = 6; /// /// 圆角 /// [Description("圆角"), Category("外观"), DefaultValue(6)] public int Radius { get => radius; set { if (radius == value) return; radius = value; Invalidate(); } } #region 阴影 Padding _padding = new Padding(0); [Description("内边距"), Category("外观"), DefaultValue(typeof(Padding), "0, 0, 0, 0")] public Padding padding { get => _padding; set { if (_padding == value) return; _padding = value; shadow_temp?.Dispose(); shadow_temp = null; OnSizeChanged(EventArgs.Empty); } } int shadow = 0; /// /// 阴影大小 /// [Description("阴影"), Category("外观"), DefaultValue(0)] public int Shadow { get => shadow; set { if (shadow == value) return; shadow = value; shadow_temp?.Dispose(); shadow_temp = null; OnSizeChanged(EventArgs.Empty); } } Color? shadowColor; /// /// 阴影颜色 /// [Description("阴影颜色"), Category("阴影"), DefaultValue(null)] [Editor(typeof(Design.ColorEditor), typeof(UITypeEditor))] public Color? ShadowColor { get => shadowColor; set { if (shadowColor == value) return; shadowColor = value; shadow_temp?.Dispose(); shadow_temp = null; Invalidate(); } } int shadowOffsetX = 0; /// /// 阴影偏移X /// [Description("阴影偏移X"), Category("阴影"), DefaultValue(0)] public int ShadowOffsetX { get => shadowOffsetX; set { if (shadowOffsetX == value) return; shadowOffsetX = value; shadow_temp?.Dispose(); shadow_temp = null; OnSizeChanged(EventArgs.Empty); } } int shadowOffsetY = 0; /// /// 阴影偏移Y /// [Description("阴影偏移Y"), Category("阴影"), DefaultValue(0)] public int ShadowOffsetY { get => shadowOffsetY; set { if (shadowOffsetY == value) return; shadowOffsetY = value; shadow_temp?.Dispose(); shadow_temp = null; OnSizeChanged(EventArgs.Empty); } } float shadowOpacity = 0.1F; /// /// 阴影透明度 /// [Description("阴影透明度"), Category("阴影"), DefaultValue(0.1F)] public float ShadowOpacity { get => shadowOpacity; set { if (shadowOpacity == value) return; if (value < 0) value = 0; else if (value > 1) value = 1; shadowOpacity = value; AnimationHoverValue = shadowOpacity; Invalidate(); } } /// /// 阴影透明度动画使能 /// [Description("阴影透明度动画使能"), Category("阴影"), DefaultValue(false)] public bool ShadowOpacityAnimation { get; set; } float shadowOpacityHover = 0.3F; /// /// 悬停阴影后透明度 /// [Description("悬停阴影后透明度"), Category("阴影"), DefaultValue(0.3F)] public float ShadowOpacityHover { get => shadowOpacityHover; set { if (shadowOpacityHover == value) return; if (value < 0) value = 0; else if (value > 1) value = 1; shadowOpacityHover = value; Invalidate(); } } TAlignMini shadowAlign = TAlignMini.None; [Description("阴影方向"), Category("阴影"), DefaultValue(TAlignMini.None)] public TAlignMini ShadowAlign { get => shadowAlign; set { if (shadowAlign == value) return; shadowAlign = value; shadow_temp?.Dispose(); shadow_temp = null; OnSizeChanged(EventArgs.Empty); } } #endregion #region 背景 Color? back; /// /// 背景颜色 /// [Description("背景颜色"), Category("外观"), DefaultValue(null)] [Editor(typeof(Design.ColorEditor), typeof(UITypeEditor))] public Color? Back { 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 箭头 int arrwoSize = 8; /// /// 箭头大小 /// [Description("箭头大小"), Category("箭头"), DefaultValue(8)] public int ArrowSize { get => arrwoSize; set { if (arrwoSize == value) return; arrwoSize = value; Invalidate(); } } TAlign arrowAlign = TAlign.None; /// /// 箭头方向 /// [Description("箭头方向"), Category("箭头"), DefaultValue(TAlign.None)] public TAlign ArrowAlign { get => arrowAlign; set { if (arrowAlign == value) return; arrowAlign = value; Invalidate(); } } #endregion #region 边框 float borderWidth = 0F; /// /// 边框宽度 /// [Description("边框宽度"), Category("边框"), DefaultValue(0F)] public float BorderWidth { get => borderWidth; set { if (borderWidth == value) return; borderWidth = value; OnSizeChanged(EventArgs.Empty); } } Color? borderColor; /// /// 边框颜色 /// [Description("边框颜色"), Category("边框"), DefaultValue(null)] [Editor(typeof(Design.ColorEditor), typeof(UITypeEditor))] public Color? BorderColor { get => borderColor; set { if (borderColor == value) return; borderColor = value; Invalidate(); } } #endregion #endregion public override Rectangle DisplayRectangle { get => ClientRectangle.DeflateRect(Padding, this, shadowAlign, borderWidth); } #region 渲染 protected override void OnPaint(PaintEventArgs e) { var rect = ClientRectangle; if (rect.Width > 0 && rect.Height > 0) { var g = e.Graphics.High(); var rect_read = ReadRectangle; float _radius = radius * Config.Dpi; using (var brush = new SolidBrush(back ?? Style.Db.BgContainer)) { using (var path = DrawShadow(g, _radius, rect, rect_read)) { g.FillPath(brush, path); if (backImage != null) g.PaintImg(rect_read, backImage, backFit, _radius, false); if (borderWidth > 0) { using (var brush_bor = new Pen(borderColor ?? Style.Db.BorderColor, borderWidth * Config.Dpi)) { g.DrawPath(brush_bor, path); } } } if (ArrowAlign != TAlign.None) g.FillPolygon(brush, ArrowAlign.AlignLines(ArrowSize, rect, rect_read)); } this.PaintBadge(g); } base.OnPaint(e); } Bitmap? shadow_temp = null; /// /// 绘制阴影 /// /// GDI /// 客户区域 /// 真实区域 GraphicsPath DrawShadow(Graphics g, float radius, Rectangle rect_client, Rectangle rect_read) { var path = rect_read.RoundPath(radius, shadowAlign); if (shadow > 0) { int shadow = (int)(Shadow * Config.Dpi), shadowOffsetX = (int)(ShadowOffsetX * Config.Dpi), shadowOffsetY = (int)(ShadowOffsetY * Config.Dpi); if (shadow_temp == null || (shadow_temp.Width != rect_client.Width || shadow_temp.Height != rect_client.Height)) { shadow_temp?.Dispose(); shadow_temp = path.PaintShadow(rect_client.Width, rect_client.Height, shadowColor ?? Style.Db.TextBase, shadow); } using (var attributes = new ImageAttributes()) { var matrix = new ColorMatrix(); if (AnimationHover) matrix.Matrix33 = AnimationHoverValue; else if (ExtraMouseHover) matrix.Matrix33 = shadowOpacityHover; else matrix.Matrix33 = shadowOpacity; attributes.SetColorMatrix(matrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap); g.DrawImage(shadow_temp, new Rectangle(rect_client.X + shadowOffsetX, rect_client.Y + shadowOffsetY, rect_client.Width, rect_client.Height), 0, 0, shadow_temp.Width, shadow_temp.Height, GraphicsUnit.Pixel, attributes); } } return path; } public override Rectangle ReadRectangle { get => ClientRectangle.DeflateRect(_padding).PaddingRect(this, shadowAlign, borderWidth); } public override GraphicsPath RenderRegion { get => ReadRectangle.RoundPath(radius * Config.Dpi); } #endregion #region 鼠标 float AnimationHoverValue = 0.1F; bool AnimationHover = false; bool _mouseHover = false; bool ExtraMouseHover { get => _mouseHover; set { if (_mouseHover == value) return; _mouseHover = value; if (Enabled && ShadowOpacityAnimation && shadow > 0 && shadowOpacityHover > 0 && shadowOpacityHover > shadowOpacity) { if (Config.Animation) { ThreadHover?.Dispose(); AnimationHover = true; float addvalue = shadowOpacityHover / 12F; if (value) { ThreadHover = new ITask(this, () => { AnimationHoverValue = AnimationHoverValue.Calculate(addvalue); if (AnimationHoverValue >= shadowOpacityHover) { AnimationHoverValue = shadowOpacityHover; return false; } Invalidate(); return true; }, 20, () => { AnimationHover = false; Invalidate(); }); } else { ThreadHover = new ITask(this, () => { AnimationHoverValue = AnimationHoverValue.Calculate(-addvalue); if (AnimationHoverValue <= shadowOpacity) { AnimationHoverValue = shadowOpacity; return false; } Invalidate(); return true; }, 20, () => { AnimationHover = false; Invalidate(); }); } } else Invalidate(); } } } public void SetMouseHover(bool val) { ExtraMouseHover = val; } #region 动画 protected override void Dispose(bool disposing) { ThreadHover?.Dispose(); Application.RemoveMessageFilter(this); shadow_temp?.Dispose(); shadow_temp = null; base.Dispose(disposing); } ITask? ThreadHover = null; #endregion protected override void OnMouseEnter(EventArgs e) { base.OnMouseEnter(e); ExtraMouseHover = true; } #region 离开监控 public bool PreFilterMessage(ref System.Windows.Forms.Message m) { if (m.Msg == 0x2a1 || m.Msg == 0x2a3) { ExtraMouseHover = ClientRectangle.Contains(PointToClient(MousePosition)); return false; } return false; } #endregion protected override void OnLeave(EventArgs e) { base.OnLeave(e); ExtraMouseHover = false; } #endregion protected override void OnHandleCreated(EventArgs e) { base.OnHandleCreated(e); Application.AddMessageFilter(this); this.AddListener(); } #region 主题变化 public void HandleEvent(EventType id, object? tag) { switch (id) { case EventType.THEME: shadow_temp?.Dispose(); shadow_temp = null; break; } } #endregion } internal class IControlDesigner : System.Windows.Forms.Design.ParentControlDesigner { } }