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

namespace Asa.Theme
{
    /// <summary>
    /// 滑轨控件
    /// </summary>
    [DefaultProperty("Value")]
    [DefaultEvent("ValueChanged")]
    public partial class FlatTrack : FlatBase
    {
        private GraphicsPath _trackPath;  //轨道路径
        private GraphicsPath _trackCurrPath;
        private RectangleF _adjustRect;    //调节器
        private GraphicsPath _adjustPath;
        private RectangleF _textRect;
        private bool _adjustDown;
        private int _min;
        private int _max;
        private int _value;
        private float _len;
        private float _step;
        private  int _radius;        //半径
        private int _diameter = 10;  //直径
        private Direction _direction = Direction.Vertical;

        private const int SPACE = 6;

        /// <summary>
        /// 滑轨控件
        /// </summary>
        public FlatTrack()
        {
            InitializeComponent();
            _min = 0;
            _max = 100;
            _value = 0;
            CalcSize();
            Refresh();
        }

        /// <summary>
        /// 最小值
        /// </summary>
        [Browsable(true), Category(""), Description("最小值"), DefaultValue(0)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        public int Min
        {
            set
            {
                _min = value;
                if (_value < _min) _value = _min;
                CalcSize();
                Refresh();
            }
            get
            {
                return _min;
            }
        }

        /// <summary>
        /// 最大值
        /// </summary>
        [Browsable(true), Category(""), Description("最大值"), DefaultValue(100)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        public int Max
        {
            set
            {
                _max = value;
                if (_value > _max) _value = _max;
                CalcSize();
                Refresh();
            }
            get
            {
                return _max;
            }
        }

        /// <summary>
        /// 当前值
        /// </summary>
        [Browsable(true), Category(""), Description("当前值"), DefaultValue(0)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        public int Value
        {
            set
            {
                _value = value;
                if (_value < _min)
                    _value = _min;
                else if (_value > _max)
                    _value = _max;
                CalcSize();
                Refresh();
                ValueChanged?.Invoke(this);
            }
            get
            {
                return _value;
            }
        }

        /// <summary>
        /// 轨道宽度
        /// </summary>
        [Browsable(true), Category(""), Description("轨道宽度"), DefaultValue(8)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        public int TrackWidth
        {
            set
            {
                _diameter = value;
                CalcSize();
                Refresh();
            }
            get
            {
                return _diameter;
            }
        }

        /// <summary>
        /// 控件的方向
        /// </summary>
        [Browsable(true), Category(""), Description("控件的方向"), DefaultValue(Direction.Vertical)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        public Direction Direction
        {
            set
            {
                _direction = value;
                CalcSize();
                Refresh();
            }
            get
            {
                return _direction;
            }
        }

        /// <summary>
        /// 当前值改变时发生的事件
        /// </summary>
        [Browsable(true), Category(""), Description("当前值改变时发生的事件")]
        public event Event.ValueChanged ValueChanged;



        /// <summary>
        /// 改变大小
        /// </summary>
        protected override void CalcSize()
        {
            _radius = _diameter / 2;
            RectangleF rect1, rect2;
            PointF pt;

            if (_direction == Direction.Vertical)
            {
                rect1 = new RectangleF(Width / 2f - _radius, SPACE, _diameter, _diameter);  //上半圆
                rect2 = new RectangleF(Width / 2f - _radius, Height - SPACE - _diameter, _diameter, _diameter);  //下半圆
                _len = rect2.Y - rect1.Y;
                _step = _len / (_max - _min);

                //轨道
                _trackPath = new GraphicsPath();
                _trackPath.AddArc(rect1, 180, 180);
                _trackPath.AddLine(rect1.Right, rect1.Y + _radius, rect2.Right, rect2.Y + _radius);
                _trackPath.AddArc(rect2, 0, 180);
                _trackPath.AddLine(rect2.X, rect2.Y + _radius, rect1.X, rect1.Y + _radius);

                //轨道当前部分
                pt = new PointF(rect1.X + _radius, rect1.Y + _radius + (_value - _min) * _step);
                _trackCurrPath = new GraphicsPath();
                _trackCurrPath.AddArc(rect1, 180, 180);
                _trackCurrPath.AddLine(rect1.Right, rect1.Y + _radius, pt.X + _radius, pt.Y);
                _trackCurrPath.AddLine(pt.X + _radius, pt.Y, pt.X - _radius, pt.Y);
                _trackCurrPath.AddLine(pt.X - _radius, pt.Y, rect1.X, rect1.Y + _radius);

                //调节器
                int r = 8;
                _adjustRect = new RectangleF(pt.X - _radius - r, pt.Y - r, _diameter + r + r, r + r);
                rect1 = new RectangleF(pt.X - _radius - r, pt.Y - r, r * 2, r * 2);
                rect2 = new RectangleF(pt.X + _radius - r, pt.Y - r, r * 2, r * 2);
                _adjustPath = new GraphicsPath();
                _adjustPath.AddArc(rect1, 90, 180);
                _adjustPath.AddLine(rect1.X + r, rect1.Y, rect2.X + r, rect2.Y);
                _adjustPath.AddArc(rect2, -90, 180);
                _adjustPath.AddLine(rect2.X + r, rect2.Bottom, rect1.X + r, rect1.Bottom);

                //数值显示
                SizeF sf = CreateGraphics().MeasureString(_value.ToString(), Common.FONT_SONG_9);
                _textRect = new RectangleF(_adjustRect.X + (_adjustRect.Width - sf.Width) / 2f, _adjustRect.Y + (_adjustRect.Height - sf.Height) / 2f + 1, sf.Width, sf.Height);
            }
            else if (_direction == Direction.Horizontal)
            {
                rect1 = new RectangleF(SPACE, Height / 2f - _radius, _diameter, _diameter);  //左半圆
                rect2 = new RectangleF(Width - SPACE - _diameter, Height / 2f - _radius, _diameter, _diameter);  //右半圆
                _len = rect2.X - rect1.X;
                _step = _len / (_max - _min);

                //轨道
                _trackPath = new GraphicsPath();
                _trackPath.AddArc(rect1, 90, 180);
                _trackPath.AddLine(rect1.X + _radius, rect1.Y, rect2.X + _radius, rect2.Y);
                _trackPath.AddArc(rect2, -90, 180);
                _trackPath.AddLine(rect2.X + _radius, rect2.Bottom, rect1.X + _radius, rect1.Bottom);

                //轨道当前部分
                pt = new PointF(rect1.X + _radius + (_value - _min) * _step, rect1.Y + _radius);
                _trackCurrPath = new GraphicsPath();
                _trackCurrPath.AddArc(rect1, 90, 180);
                _trackCurrPath.AddLine(rect1.X + _radius, rect1.Y, pt.X, pt.Y - _radius);
                _trackCurrPath.AddLine(pt.X, pt.Y - _radius, pt.X, pt.Y + _radius);
                _trackCurrPath.AddLine(pt.X, pt.Y + _radius, rect1.X + _radius, rect1.Bottom);

                //调节器
                int r = 8;
                _adjustRect = new RectangleF(pt.X - r, pt.Y - _radius - r, r + r, _diameter + r + r);
                rect1 = new RectangleF(pt.X - r, pt.Y - _radius - r, r * 2, r * 2);
                rect2 = new RectangleF(pt.X - r, pt.Y + _radius - r, r * 2, r * 2);
                _adjustPath = new GraphicsPath();
                _adjustPath.AddArc(rect1, 180, 180);
                _adjustPath.AddLine(rect1.Right, rect1.Y + r, rect2.Right, rect2.Y + r);
                _adjustPath.AddArc(rect2, 0, 180);
                _adjustPath.AddLine(rect2.X, rect2.Y + r, rect1.X, rect1.Y + r);
            }
        }

        private void FlatTrack_Paint(object sender, PaintEventArgs e)
        {
            //双缓冲
            BufferedGraphicsContext current = BufferedGraphicsManager.Current;
            BufferedGraphics bg = current.Allocate(CreateGraphics(), DisplayRectangle);
            Graphics g = bg.Graphics;

            //高质量
            g.SmoothingMode = SmoothingMode.HighQuality;
            g.CompositingQuality = CompositingQuality.HighQuality;
            g.InterpolationMode = InterpolationMode.HighQualityBicubic;

            g.Clear(Common.BACK_COLOR);
            g.FillPath(Common.BLUE_BRUSH, _trackCurrPath);

            if (Inside)
                g.DrawPath(Common.BLUE_PEN, _trackPath);
            else
                g.DrawPath(Common.BORDER_PEN, _trackPath);

            g.FillPath(Common.FORE_BRUSH, _adjustPath);
            if (_direction == Direction.Vertical)
                g.DrawString(_value.ToString(), Common.FONT_SONG_9, Common.BACK_BRUSH, _textRect);


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

        private void FlatTrack_MouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                bool rtn = _adjustRect.Contains(e.Location);
                if (rtn != _adjustDown)
                {
                    _adjustDown = rtn;
                    Refresh();
                }
            }
        }

        private void FlatTrack_MouseMove(object sender, MouseEventArgs e)
        {
            if (_adjustDown)
            {
                int tt = 0;
                if (_direction == Direction.Vertical)
                    tt = e.Y;
                else if (_direction == Direction.Horizontal)
                    tt = e.X;

                float val = (tt - SPACE - _radius) / _step + _min;
                int n = (int)val;
                if (n == _value) return;
                Value = n;
            }
        }

        private void FlatTrack_MouseUp(object sender, MouseEventArgs e)
        {
            if (_adjustDown)
            {
                _adjustDown = false;
                Refresh();
            }
        }

    }
}