FaceRadio.cs 10.0 KB
using System;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;

namespace FaceControl
{
    [DefaultProperty("Text")]
    [DefaultEvent("CheckedChanged")]
    public partial class FaceRadio : ControlBase
    {
        private bool mouseDown = false;
        private RectangleF ringOutRect = new RectangleF();
        private RectangleF ringInRect = new RectangleF();
        private RectangleF ringPoint = new RectangleF();
        private RectangleF textRect = new RectangleF();
        private GraphicsPath borderPath = new GraphicsPath();

        private bool _check = false;
        private int _ringWidth = 18;

        private const int SPACE = 6;  //图片与文字的间隔

        public FaceRadio()
        {
            InitializeComponent();
        }


        #region 事件
        [Browsable(true), Category("杂项"), Description("当checked属性更改值时发生")]
        public event EventHandler CheckedChanged;
        #endregion

        #region 属性
        [Browsable(true), Category("外观"), Description("控件上环形开关的宽度"), DefaultValue(18)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        public int RingWidth
        {
            get => _ringWidth;
            set
            {
                _ringWidth = value;
                CalcSize();
                Refresh();
            }
        }

        [Browsable(true), Category(""), Description("单选按钮是否已选中"), DefaultValue(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        public bool Checked
        {
            set
            {
                if (_check != value)
                {
                    _check = value;
                    CalcSize();
                    Refresh();
                }
                if (_check)
                    SetGroup();
                CheckedChanged?.Invoke(this, new EventArgs());
            }
            get
            {
                return _check;
            }
        }

        [Browsable(true), Category(""), Description("相同的内容为一组,同一组的单选按钮只能选中一个。"), DefaultValue("")]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        public string Group { set; get; }

        #endregion


        protected override void CalcSize()
        {
            base.CalcSize();

            CalcTextLocation();
            CalcShape();
        }

        protected override void DrawEnabled(Graphics g)
        {
            base.DrawEnabled(g);

            //控件边框
            if (CursorInside)
            {
                if (_check)
                {
                    if (mouseDown)
                        g.FillEllipse(new SolidBrush(theme.DOWN_COLOR), ringOutRect);
                    else
                        g.FillEllipse(new SolidBrush(ForeColor), ringOutRect);
                }
                else
                {
                    if (mouseDown)
                        g.FillEllipse(new SolidBrush(ForeColor), ringOutRect);
                    else
                        g.FillEllipse(new SolidBrush(theme.DOWN_COLOR), ringOutRect);
                }
                g.FillEllipse(new SolidBrush(theme.BACK_COLOR), ringInRect);
                if (BorderWidth > 0)
                    g.DrawPath(borderInsidePen, borderPath);
            }
            else
            {
                g.FillPath(new SolidBrush(BackColor), borderPath);
                if (_check)
                {
                    g.FillEllipse(new SolidBrush(theme.DOWN_COLOR), ringOutRect);
                }
                else
                {
                    g.FillEllipse(new SolidBrush(ForeColor), ringOutRect);
                }
                g.FillEllipse(new SolidBrush(theme.BACK_COLOR), ringInRect);
                if (BorderWidth > 0)
                    g.DrawPath(borderOutsidePen, borderPath);
            }

            //开关圆点
            if (_check)
                g.FillEllipse(new SolidBrush(ForeColor), ringPoint);

            //文字
            g.DrawString(Text, Font, new SolidBrush(ForeColor), textRect);

        }

        protected override void DrawDisabled(Graphics g)
        {
            base.DrawDisabled(g);

            //控件边框
            g.FillEllipse(new SolidBrush(theme.OVER_COLOR), ringOutRect);
            g.FillEllipse(new SolidBrush(theme.BACK_COLOR), ringInRect);
            if (BorderWidth > 0)
                g.DrawPath(borderOutsidePen, borderPath);

            //开关圆点
            if (_check)
                g.FillEllipse(new SolidBrush(theme.OVER_COLOR), ringPoint);

            //文字
            g.DrawString(Text, Font, new SolidBrush(theme.LOST_FOCUS_COLOR), textRect);
        }

        private void SetGroup()
        {
            if (Parent == null) return;
            foreach (Control ctl in Parent.Controls)
            {
                if (ctl is FaceRadio)
                {
                    FaceRadio rdo = (FaceRadio)ctl;
                    if (rdo == this) continue;
                    if (rdo.Group == Group)
                    {
                        if (rdo.Checked)
                        {
                            rdo.Checked = false;
                            break;
                        }
                    }
                }
            }
        }

        private void CalcShape()
        {
            borderPath = new GraphicsPath();
            float n;

            switch (FaceShape)
            {
                case Model.ButtonShape.Rectangle:
                    borderPath.AddRectangle(borderRect);
                    break;
                case Model.ButtonShape.RoundRectangle:
                    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);
                    break;
                case Model.ButtonShape.Ellipse:
                    borderPath.AddEllipse(borderRect);
                    break;
                case Model.ButtonShape.EllipseRectangle:
                    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);
                    break;
                case Model.ButtonShape.Circle:
                    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);
                    break;
            }
        }

        private void CalcTextLocation()
        {
            if (string.IsNullOrEmpty(Text)) return;
            Graphics g = CreateGraphics();
            SizeF sf = g.MeasureString(Text, Font);
            ringOutRect = new RectangleF(0, (Height - _ringWidth) / 2f, _ringWidth, _ringWidth);
            textRect = new RectangleF(0, (Height - sf.Height) / 2f, sf.Width, sf.Height);
            float x;

            switch (TextAlign)
            {
                case HorizontalAlignment.Left:
                    x = BorderWidth;
                    ringOutRect.X = x;
                    x += _ringWidth + SPACE;
                    textRect.X = x;
                    break;
                case HorizontalAlignment.Center:
                    x = (Width - sf.Width - _ringWidth - SPACE) / 2f;
                    ringOutRect.X = x;
                    x += _ringWidth + SPACE;
                    textRect.X = x;
                    break;
                case HorizontalAlignment.Right:
                    x = Width - BorderWidth - sf.Width;
                    textRect.X = x;
                    x -= (SPACE + _ringWidth);
                    ringOutRect.X = x;
                    break;
            }

            float w = _ringWidth / 6f;
            ringInRect = new RectangleF(ringOutRect.X + w, ringOutRect.Y + w, w * 4, w * 4);
            ringPoint = new RectangleF(ringOutRect.X + w * 2, ringOutRect.Y + w * 2, w * 2, w * 2);
        }

        private void FaceRadio_MouseDown(object sender, MouseEventArgs e)
        {
            if (!Enabled) return;
            if (e.Button == MouseButtons.Left)
            {
                mouseDown = true;
                _check = !_check;
                Refresh();

                if (_check)
                    SetGroup();
            }
        }

        private void FaceRadio_MouseUp(object sender, MouseEventArgs e)
        {
            if (!Enabled) return;
            if (e.Button == MouseButtons.Left)
            {
                mouseDown = false;
                Refresh();
                CheckedChanged?.Invoke(this, new EventArgs());
            }
        }

        private void FaceRadio_MouseMove(object sender, MouseEventArgs e)
        {
            //buttonOver = borderPath.IsVisible(e.Location);
            //Refresh();
        }

    }
}