SurHScrollBar.cs 8.0 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.Face
{
    /// <summary>
    /// 水平滚动条
    /// </summary>
    [DefaultProperty("Value")]
    [DefaultEvent("ValueChanged")]
    public partial class SurHScrollBar : BaseCtl
    {
        private Rectangle _button1 = new Rectangle();
        private Rectangle _button2 = new Rectangle();
        private RectangleF _slider = new RectangleF();
        private GraphicsPath _btnShape1 = new GraphicsPath();
        private GraphicsPath _btnShape2 = new GraphicsPath();
        private int _over = -1;
        private int _down = -1;
        private int _oldX = -1;
        
        private int _max = 100;
        private int _min = 0;
        private int _value = 0;
        private float _step = SLIDER_STEP;

        private const int BTN_SIZE = 25;
        private const int SLIDER_MIN = 15;
        private const int SLIDER_STEP = 2;

        private static readonly Color BACK = Color.FromArgb(40, 40, 40);
        private static readonly Brush BTN_BRUSH = new SolidBrush(Color.FromArgb(60, 60, 60));
        private static readonly Brush SLIDER_BRUSH = new SolidBrush(Color.FromArgb(60, 60, 60));
        private static readonly Brush SLIDER_OVER = new SolidBrush(Color.FromArgb(70, 70, 70));


        /// <summary>
        /// 水平滚动条
        /// </summary>
        public SurHScrollBar()
        {
            InitializeComponent();
            BackColor = BACK;
        }


        //==========事件==========
        /// <summary>
        /// 在控件的值更改时发生
        /// </summary>
        [Browsable(true), Category(""), Description("在控件的值更改时发生")]
        public event MyEvent.Changed ValueChanged;


        //==========属性==========
        /// <summary>
        /// 可滚动范围的上限值
        /// </summary>
        [Browsable(true), Category(""), Description("可滚动范围的上限值"), DefaultValue(100)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        public int Maximum
        {
            set
            {
                if (value < _min)
                    _max = _min + 1;
                else
                    _max = value;
                if (_value > _max)
                    _value = _max;
                CalcSize();
                Refresh();
            }
            get => _max;
        }

        /// <summary>
        /// 可滚动范围的下限值
        /// </summary>
        [Browsable(true), Category(""), Description("可滚动范围的下限值"), DefaultValue(0)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        public int Minimum
        {
            set
            {
                if (value >= _max)
                    _min = _max - 1;
                else if (value < 0)
                    _min = 0;
                else
                    _min = value;
                if (_value < _min)
                    _value = _min;
                CalcSize();
                Refresh();
            }
            get => _min;
        }

        /// <summary>
        /// 滚动框位置表示的值
        /// </summary>
        [Browsable(true), Category(""), Description("滚动框位置表示的值"), DefaultValue(0)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        public int Value
        {
            set
            {
                if (value >= _min && value <= _max)
                {
                    _value = value;
                    CalcSize();
                    Refresh();
                    ValueChanged?.Invoke(this);
                }
            }
            get => _value;
        }


        //==========私有==========
        /// <summary>
        /// 计算位置大小
        /// </summary>
        protected override void CalcSize()
        {
            base.CalcSize();

            _button1 = new Rectangle(0, 0, BTN_SIZE, Height);
            _button2 = new Rectangle(Width - BTN_SIZE, 0, BTN_SIZE, Height);
            _btnShape1 = Shape.ControlTriangle(_button1, 6, Direction.Left);
            _btnShape2 = Shape.ControlTriangle(_button2, 6, Direction.Right);

            int w = Width - BTN_SIZE - BTN_SIZE - _max * SLIDER_STEP;
            if (w < SLIDER_MIN)
            {
                w = SLIDER_MIN;
                _step = (Width - BTN_SIZE - BTN_SIZE - w) / (float)_max;
            }
            else
            {
                _step = SLIDER_STEP;
            }


            _slider = new RectangleF(BTN_SIZE + _value * _step, 0, w, Height);

        }

        private void ScrollBar_MouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                if (_over > -1)
                {
                    _oldX = e.Y;
                    _down = _over;
                    Refresh();
                }
            }
        }

        private void ScrollBar_MouseUp(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                if (_down == 0)
                {
                    if (_value > _min)
                    {
                        Value--;
                        ValueChanged?.Invoke(this);
                    }
                }
                else if (_down == 2)
                {
                    if (_value < _max)
                    {
                        Value++;
                        ValueChanged?.Invoke(this);
                    }
                }

                _down = -1;
                Refresh();
            }
        }

        private void ScrollBar_MouseMove(object sender, MouseEventArgs e)
        {
            int n = -1;

            if (e.Button == MouseButtons.Left)
            {
                if (_down != 1) return;
                n = Convert.ToInt32((e.X - _oldX) / _step);
                _oldX += Convert.ToInt32(n * _step);
                Value += n;
                ValueChanged?.Invoke(this);
            }
            else
            {
                if (_button1.Contains(e.Location))
                    n = 0;
                else if (_slider.Contains(e.Location))
                    n = 1;
                else if (_button2.Contains(e.Location))
                    n = 2;
                if (_over != n)
                {
                    _over = n;
                    Refresh();
                }
            }
        }

        private void ScrollBar_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(BACK);  //背景

            if (!Inside)
            {
                _over = -1;
                _down = -1;
            }

            if (_down == 0)
                g.FillRectangle(Common.BLUE_BRUSH, _button1);
            else if (_over == 0)
                g.FillRectangle(BTN_BRUSH, _button1);
            if (_down == 1)
                g.FillRectangle(Common.BLUE_BRUSH, _slider);
            else if (_over == 1)
                g.FillRectangle(SLIDER_OVER, _slider);
            else
                g.FillRectangle(SLIDER_BRUSH, _slider);
            if (_down == 2)
                g.FillRectangle(Common.BLUE_BRUSH, _button2);
            else if (_over == 2)
                g.FillRectangle(BTN_BRUSH, _button2);
            g.FillPath(Common.FORE_BRUSH, _btnShape1);
            g.FillPath(Common.FORE_BRUSH, _btnShape2);

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

        private void SurScrollBar_Load(object sender, EventArgs e)
        {
            BackColor = BACK;
        }


    }
}