ControlBase.cs 14.1 KB
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace Asa.FaceControl
{
    public partial class ControlBase : UserControl
    {
        //=====属性变量=====
        private int _borderWidth = 2;
        private ControlShape _faceShape = ControlShape.Rectangle;

        //=====私有变量=====
        private readonly Dictionary<ControlShape, Action> dicShape;
        private bool borderEnterChanged;

        //=====子类变量=====
        internal RectangleF borderRect;
        internal GraphicsPath borderPath;
        internal IFaceThemeColor theme;
        internal bool borderEnter;
        internal bool mouseLeftDown;
        internal bool mouseRightDown;
        internal StringFormat stringFormat = new(StringFormatFlags.NoClip);
        internal readonly SolidBrush BRUSH_DISABLED;

        public ControlBase()
        {
            InitializeComponent();

            theme = new DarkThemeColor();
            BRUSH_DISABLED = new SolidBrush(theme.DISABLED);

            AutoScaleMode = AutoScaleMode.None;
            BackColor = theme.BACK;
            ForeColor = theme.FORE;
            Padding = new Padding(3);

            dicShape = new Dictionary<ControlShape, Action>
            {
                { ControlShape.Rectangle, ShapeRectangle },
                { ControlShape.RoundRectangle, ShapeRoundRectangle },
                { ControlShape.Ellipse, ShapeEllipse },
                { ControlShape.EllipseRectangle, ShapeEllipseRectangle },
                { ControlShape.Circle, ShapeCircle }
            };
        }



        //=====公共方法=====
        public Bitmap ToImage()
        {
            IntPtr hSrce = API.GetWindowDC(Handle);
            IntPtr hDest = API.CreateCompatibleDC(hSrce);
            IntPtr hBmp = API.CreateCompatibleBitmap(hSrce, Width, Height);
            IntPtr hOldBmp = API.SelectObject(hDest, hBmp);
            if (API.BitBlt(hDest, 0, 0, Width, Height, hSrce, 0, 0, CopyPixelOperation.SourceCopy | CopyPixelOperation.CaptureBlt))
            {
                Bitmap bmp = Image.FromHbitmap(hBmp);
                API.SelectObject(hDest, hOldBmp);
                API.DeleteObject(hBmp);
                API.DeleteDC(hDest);
                API.ReleaseDC(Handle, hSrce);
                return bmp;
            }
            return null;
        }



        //=====子类方法=====
        protected virtual void CalcSize()
        {
            //边框位置
            float x = _borderWidth / 2f;
            float y = _borderWidth / 2f;
            float width = ClientSize.Width - _borderWidth - 1;
            float height = ClientSize.Height - _borderWidth - 1;
            borderRect = new RectangleF(x, y, width, height);

            //边框路径
            borderPath = new GraphicsPath();
            dicShape[_faceShape].Invoke();
        }

        protected virtual void DrawEnabled(Graphics g)
        {
            borderEnterChanged = borderEnter;
        }

        protected virtual void DrawDisabled(Graphics g)
        {
        }

        public virtual void LostFocused()
        {
        }



        //=====事件=====
        [Browsable(true)]
        public new event EventHandler TextChanged;



        //=====属性=====
        [Browsable(true)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        public int BorderWidth
        {
            get => _borderWidth;
            set
            {
                _borderWidth = value > 0 ? value : 0;
                CalcSize();
                Refresh();
            }
        }

        //[Browsable(true)]
        //public override Color BackColor
        //{
        //    get => base.BackColor;
        //    set
        //    {
        //        base.BackColor = value;
        //        Refresh();
        //    }
        //}

        //[Browsable(true)]
        //public override Color ForeColor
        //{
        //    get => base.ForeColor;
        //    set
        //    {
        //        base.ForeColor = value;
        //        Refresh();
        //    }
        //}

        [Browsable(true)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        public new ControlShape BorderStyle
        {
            get => _faceShape;
            set
            {
                _faceShape = value;
                CalcSize();
                Refresh();
            }
        }

        [Browsable(true)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        public override Font Font
        {
            get => base.Font;
            set
            {
                base.Font = value;
                CalcSize();
                Refresh();
            }
        }

        [Browsable(true)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        public override string Text
        {
            get => base.Text;
            set
            {
                base.Text = value;
                CalcSize();
                Refresh();
                TextChanged?.Invoke(this, new EventArgs());
            }
        }

        //[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        //public new string AccessibleDescription { set => base.AccessibleDescription = value; get => base.AccessibleDescription; }
        
        //[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        //public new string AccessibleName { set => base.AccessibleName = value; get => base.AccessibleName; }

        //[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        //public new AccessibleRole AccessibleRole { set => base.AccessibleRole = value; get => base.AccessibleRole; }

        //[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        //public new bool AllowDrop { set => base.AllowDrop = value; get => base.AllowDrop; }

        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        public new AutoScaleMode AutoScaleMode { set => base.AutoScaleMode = AutoScaleMode.None; get => AutoScaleMode.None; }
       
        //[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        //public new bool AutoScroll { get => base.AutoScroll; set => base.AutoScroll = value; }
        //[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        //public new Size AutoScrollMargin { get => base.AutoScrollMargin; set => base.AutoScrollMargin = value; }
        //[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        //public new Size AutoScrollMinSize { get => base.AutoScrollMinSize; set => base.AutoScrollMinSize = value; }
        //[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        //public new bool AutoSize { get => base.AutoSize; set => base.AutoSize = value; }
        //[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        //public new AutoSizeMode AutoSizeMode { get => base.AutoSizeMode; set => base.AutoSizeMode = value; }
        //[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        //public new AutoValidate AutoValidate { get => base.AutoValidate; set => base.AutoValidate = value; }
        //[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        //public new Image BackgroundImage { get => base.BackgroundImage; set => base.BackgroundImage = value; }
        //[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        //public new ImageLayout BackgroundImageLayout { get => base.BackgroundImageLayout; set => base.BackgroundImageLayout = value; }
        //[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        //public new bool CausesValidation { get => base.CausesValidation; set => base.CausesValidation = value; }
        //[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        //public new ContextMenuStrip ContextMenuStrip { get => base.ContextMenuStrip; set => base.ContextMenuStrip = value; }
        //[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        //public new Cursor Cursor { get => base.Cursor; set => base.Cursor = value; }
        //[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        //public new bool DoubleBuffered { get => base.DoubleBuffered; set => base.DoubleBuffered = value; }
        //[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        //public new ImeMode ImeMode { get => base.ImeMode; set => base.ImeMode = value; }
        //[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        //public new Size MaximumSize { get => base.MaximumSize; set => base.MaximumSize = value; }
        //[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        //public new Size MinimumSize { get => base.MinimumSize; set => base.MinimumSize = value; }
        //[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        //public new RightToLeft RightToLeft { get => base.RightToLeft; set => base.RightToLeft = value; }
        //[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        //public new bool UseWaitCursor { get => base.UseWaitCursor; set => base.UseWaitCursor = value; }










        private void ShapeRectangle()
        {
            borderPath.AddRectangle(borderRect);
        }

        private void ShapeRoundRectangle()
        {
            float n = borderRect.Height / 8f;
            borderPath.AddLine(borderRect.X + n, borderRect.Y, borderRect.Right - n, borderRect.Y);
            borderPath.AddArc(borderRect.Right - n - n, borderRect.Y, n + n, n + n, 270, 90);
            borderPath.AddLine(borderRect.Right, borderRect.Y + n, borderRect.Right, borderRect.Bottom - n);
            borderPath.AddArc(borderRect.Right - n - n, borderRect.Bottom - n - n, n + n, n + n, 0, 90);
            borderPath.AddLine(borderRect.Right - n, borderRect.Bottom, borderRect.X + n, borderRect.Bottom);
            borderPath.AddArc(borderRect.X, borderRect.Bottom - n - n, n + n, n + n, 90, 90);
            borderPath.AddLine(borderRect.X, borderRect.Bottom - n, borderRect.X, borderRect.Y + n);
            borderPath.AddArc(borderRect.X, borderRect.Y, n + n, n + n, 180, 90);

        }

        private void ShapeEllipse()
        {
            borderPath.AddEllipse(borderRect);
        }

        private void ShapeEllipseRectangle()
        {
            float n = borderRect.Height / 2f;
            borderPath.AddLine(borderRect.X + n, borderRect.Y, borderRect.Right - n, borderRect.Y);
            borderPath.AddArc(borderRect.Right - n - n, borderRect.Y, n + n, n + n, 270, 180);
            borderPath.AddLine(borderRect.Right - n, borderRect.Bottom, borderRect.X + n, borderRect.Bottom);
            borderPath.AddArc(borderRect.X, borderRect.Y, n + n, n + n, 90, 180);
        }

        private void ShapeCircle()
        {
            if (borderRect.Width > borderRect.Height)
                borderPath.AddEllipse((borderRect.Width - borderRect.Height) / 2f, borderRect.Y, borderRect.Height, borderRect.Height);
            else
                borderPath.AddEllipse(borderRect.X, (borderRect.Height - borderRect.Width) / 2f, borderRect.Width, borderRect.Width);
        }

        private void DrawBorder(Graphics g)
        {
            //边框以外的部分
            Region reg = new(ClientRectangle);
            reg.Exclude(borderPath);
            g.FillRegion(new SolidBrush(theme.BACK), reg);

            //边框
            if (_borderWidth > 0)
            {
                Color color = theme.DISABLED;
                if (Enabled)
                    color = borderEnter ? theme.BORDER_ENTER : theme.BORDER_LEAVE;
                Pen pen = new(color, _borderWidth);
                g.DrawPath(pen, borderPath);
            }
        }



        protected override void WndProc(ref Message m)
        {
            if (m.Msg == 0x0014)  //禁掉清除背景消息
                return;
            base.WndProc(ref m);
        }

        private void ControlBase_Load(object sender, EventArgs e)
        {
            CalcSize();
            Refresh();
        }

        private void ControlBase_Resize(object sender, EventArgs e)
        {
            CalcSize();
            Refresh();
        }

        private void ControlBase_Paint(object sender, PaintEventArgs e)
        {
            BufferedGraphicsContext current = BufferedGraphicsManager.Current;
            BufferedGraphics bg = current.Allocate(e.Graphics, e.ClipRectangle);
            Graphics g = bg.Graphics;
            g.SmoothingMode = SmoothingMode.HighQuality;
            g.CompositingQuality = CompositingQuality.HighQuality;
            g.InterpolationMode = InterpolationMode.HighQualityBicubic;
            g.Clear(BackColor);  //背景

            if (Enabled)
                DrawEnabled(g);
            else
                DrawDisabled(g);
            DrawBorder(g);

            bg.Render();
            bg.Dispose();
        }

        private void ControlBase_MouseEnter(object sender, EventArgs e)
        {
            //cursorInside = true;
        }

        private void ControlBase_MouseLeave(object sender, EventArgs e)
        {
            //cursorInside = false;

            borderEnter = false;
            Refresh();
        }

        private void ControlBase_MouseDown(object sender, MouseEventArgs e)
        {
            if (TopLevelControl is FormBase frm)
                frm.SetLostFocus(frm, Handle);

            if (e.Button == MouseButtons.Left)
            {
                mouseLeftDown = true;
                mouseRightDown = false;
            }
            else if (e.Button == MouseButtons.Right)
            {
                mouseLeftDown = false;
                mouseRightDown = true;
            }
            Refresh();
        }

        private void ControlBase_MouseUp(object sender, MouseEventArgs e)
        {
            mouseLeftDown = false;
            mouseRightDown = false;
            Refresh();
        }

        private void ControlBase_MouseMove(object sender, MouseEventArgs e)
        {
            borderEnter = borderPath.IsVisible(e.Location);
            if (borderEnterChanged != borderEnter)
                Refresh();
        }
    }
}