using ryControls.Skin;
using System;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;

namespace ryControls
{
    /// <summary>
    /// 控件的状态。
    /// </summary>
    public enum ControlState
    {
        /// <summary>
        ///  正常
        /// </summary>
        Normal,
        /// <summary>
        /// 鼠标经过
        /// </summary>
        Hover,
        /// <summary>
        /// 鼠标按下
        /// </summary>
        Pressed,
    }
    /// <summary>
    /// 鼠标的当前位置
    /// </summary>
    public enum ButtonMousePosition
    {
        /// <summary>
        /// 
        /// </summary>
        None,
        /// <summary>
        /// 
        /// </summary>
        Button,
        /// <summary>
        /// 
        /// </summary>
        Splitebutton,
    }
    /// <summary>
    /// 美化按钮
    /// </summary>
    public class ButtonEx : Button
    {
        private Color _baseColor = Color.FromArgb(12, 125, 182);//基颜色
        private Color _foreColor = Color.White;//字体颜色
        private ControlState _controlState;//控件状态
        private int _imageWidth = 16;
        private RoundStyle _roundStyle = RoundStyle.All;//圆角
        private int _radius = 8;                        //圆角半径
        /// <summary>
        /// 普通按钮矩形位置
        /// </summary>
        internal Rectangle ButtonRect
        {
            get
            {
                if (ShowSpliteButton)
                {
                    return new Rectangle(0, 0, ClientRectangle.Width - SpliteButtonWidth, ClientRectangle.Height);
                }
                else
                {
                    return new Rectangle(0,0,Width,Height);
                }
            }
        }
        /// <summary>
        ///美化按钮
        /// </summary>
        public ButtonEx() : base()
        {
            ForeColor = Color.White;
            this.SetStyle(
                ControlStyles.UserPaint |  //控件自行绘制，而不使用操作系统的绘制
                ControlStyles.AllPaintingInWmPaint | //忽略擦出的消息，减少闪烁。
                ControlStyles.OptimizedDoubleBuffer |//在缓冲区上绘制，不直接绘制到屏幕上，减少闪烁。
                ControlStyles.ResizeRedraw | //控件大小发生变化时，重绘。                  
                ControlStyles.SupportsTransparentBackColor, true);//支持透明背景颜色
        }
        private int _spliteButtonWidth = 18;
        /// <summary>
        /// 分割按钮的宽度
        /// </summary>
        [DefaultValue(18)]
        [Description("分割按钮的宽度")]
        public int SpliteButtonWidth
        {
            get { return _spliteButtonWidth; }
            set
            {
                if (_spliteButtonWidth != value)
                {
                    _spliteButtonWidth = value;
                    base.Invalidate();
                }
            }
        }
        private bool _showSpliteButton = false;
        /// <summary>
        /// 是否启用分割按钮
        /// </summary>
        [DefaultValue(false)]
        [Description("是否启用分割按钮")]
        public bool ShowSpliteButton
        {
            get { return _showSpliteButton; }
            set
            {
                if (_showSpliteButton != value)
                {
                    _showSpliteButton = value;
                    base.Invalidate();
                }
            }
        }
        private bool _UseDefSkin = true;
        /// <summary>
        ///优先使用默认皮肤
        /// </summary>
        [Description("优先使用默认皮肤")]
        [DefaultValue(typeof(bool), "true")]
        public bool UseDefSkin
        {
            get
            {
                return _UseDefSkin;
            }
            set
            {
                _UseDefSkin = value;
                base.Invalidate();
            }
        }
        /// <summary>
        ///按钮基础背景色
        /// </summary>
        [Description("按钮基础背景色")]
        [DefaultValue(typeof(Color), "12, 125, 182")]
        public Color BaseColor
        {
            get
            {
                if(SkinCommon.UseDefSkin && UseDefSkin)
                {
                    return SkinCommon.ButtonSkin.BackColor;
                }
                return _baseColor;
            }
            set
            {
                _baseColor = value;
                base.Invalidate();
            }
        }
        /// <summary>
        ///按钮字体颜色
        /// </summary>
        [Description("按钮字体颜色")]
        [DefaultValue(typeof(Color), "255, 255, 255")]
        public new Color ForeColor
        {
            get
            {
                if (SkinCommon.UseDefSkin && UseDefSkin)
                {
                    return SkinCommon.ButtonSkin.ForeColor;
                }
                return _foreColor;
            }
            set
            {
                _foreColor = value;
                base.Invalidate();
            }
        }
        /// <summary>
        ///图片宽度,默认值为18px，最小12px
        /// </summary>
        [Description("图片宽度,默认值为18px，最小12px")]
        [DefaultValue(16)]//默认值为18px，最小12px
        public int ImageWidth
        {
            get { return _imageWidth; }
            set
            {
                if (value != _imageWidth)
                {

                    _imageWidth = value < 12 ? 12 : value;
                    base.Invalidate();
                }
            }
        }
        /// <summary>
        ///圆角的位置,默认全部都是圆角 
        /// </summary>
        [Description("圆角的位置,默认全部都是圆角")]
        [DefaultValue(typeof(RoundStyle), "1")]//默认全部都是圆角
        public RoundStyle RoundStyle
        {
            get { return _roundStyle; }
            set
            {
                if (_roundStyle != value)
                {
                    _roundStyle = value;
                    base.Invalidate();
                }
            }
        }
        /// <summary>
        ///设置圆角半径 
        /// </summary>
        [Description("圆角半径")]
        [DefaultValue(8)]//设置圆角半径，默认值为8，最小值为4px
        public int Radius
        {
            get { return _radius; }
            set
            {
                if (_radius != value)
                {
                    _radius = value < 4 ? 4 : value;
                    base.Invalidate();
                }
            }
        }
        private bool _ColorGradient = false;
        /// <summary>
        /// 背景色是否渐变
        /// </summary>
        [DefaultValue(false)]
        [Description("背景色是否渐变")]
        public bool ColorGradient
        {
            get 
            {
                if (SkinCommon.UseDefSkin && UseDefSkin)
                {
                    return SkinCommon.ButtonSkin.ColorGradient;
                }
                return _ColorGradient; 
            }
            set
            {
                if (value != _ColorGradient)
                {

                    _ColorGradient = value;
                    base.Invalidate();
                }
            }
        }
        private int _imageHeight = 16;
        /// <summary>
        /// 图片高度
        /// </summary>
        [DefaultValue(16)]
        [Description("图片高度")]
        public int ImageHeight
        {
            get { return _imageHeight; }
            set
            {
                if (value != _imageHeight)
                {

                    _imageHeight = value < 12 ? 12 : value;
                    base.Invalidate();
                }
            }
        }
        private int _imageTextSpace = 2;
        /// <summary>
        /// 图片与文字之间的间距
        /// </summary>
        [DefaultValue(2)]
        [Description("图片与文字之间的间距")]
        public int ImageTextSpace
        {
            get { return _imageTextSpace; }
            set
            {
                if (_imageTextSpace != value)
                {
                    _imageTextSpace = value < 0 ? 0 : value;
                    base.Invalidate();
                }
            }
        }
        private bool _pressOffset = true;
        /// <summary>
        /// 当鼠标按下时图片和文字是否产生偏移
        /// </summary>
        [DefaultValue(true)]
        [Description("当鼠标按下时图片和文字是否产生偏移")]
        public bool PressOffset
        {
            get { return _pressOffset; }
            set
            {
                _pressOffset = value;
            }
        }
        internal ControlState ControlState  //控件的状态
        {
            get { return _controlState; }
            set
            {
                if (_controlState != value)
                {
                    _controlState = value;
                    base.Invalidate();
                }
            }
        }
        /// <summary>
        /// 鼠标进入时
        /// </summary>
        /// <param name="e"></param>
        protected override void OnMouseEnter(EventArgs e)//鼠标进入时
        {
            base.OnMouseEnter(e);
            ControlState = ControlState.Hover;//正常
        }
        /// <summary>
        /// 鼠标离开
        /// </summary>
        /// <param name="e"></param>
        protected override void OnMouseLeave(EventArgs e)//鼠标离开
        {
            base.OnMouseLeave(e);
            ControlState = ControlState.Normal;//正常
        }
        /// <summary>
        /// 鼠标按下
        /// </summary>
        /// <param name="e"></param>
        protected override void OnMouseDown(MouseEventArgs e)//鼠标按下
        {
            base.OnMouseDown(e);
            if (e.Button == MouseButtons.Left && e.Clicks == 1)//鼠标左键且点击次数为1
            {
                ControlState = ControlState.Pressed;//按下的状态
            }
        }
        /// <summary>
        /// 鼠标弹起
        /// </summary>
        /// <param name="e"></param>
        protected override void OnMouseUp(MouseEventArgs e)//鼠标弹起
        {
            base.OnMouseUp(e);
            if (e.Button == MouseButtons.Left && e.Clicks == 1)
            {
                if (ClientRectangle.Contains(e.Location))//控件区域包含鼠标的位置
                {
                    ControlState = ControlState.Hover;
                }
                else
                {
                    ControlState = ControlState.Normal;
                }
            }
        }
        private ButtonMousePosition _mousePosition;

        /// <summary>
        /// 鼠标当前所在位置
        /// </summary>
        internal ButtonMousePosition CurrentMousePosition
        {
            get { return _mousePosition; }
            set
            {
                if (_mousePosition != value)
                {
                    _mousePosition = value;
                    base.Invalidate();
                }
            }
        }

        /// <summary>
        /// 获取图像以及文字的位置
        /// </summary>
        /// <param name="imageRect"></param>
        /// <param name="textRect"></param>
        /// <param name="g"></param>
        private void CalculateRect(
            out Rectangle imageRect, out Rectangle textRect, Graphics g)
        {
            imageRect = Rectangle.Empty;
            textRect = Rectangle.Empty;
            SizeF textSize = g.MeasureString(Text, Font);
            if (Image == null)
            {
                switch (TextAlign)
                {
                    case ContentAlignment.BottomCenter:
                        textRect = new Rectangle((ButtonRect.Width - (int)textSize.Width) / 2, Height - (int)textSize.Height - 3, (int)textSize.Width, (int)textSize.Height);
                        break;
                    case ContentAlignment.BottomLeft:
                        textRect = new Rectangle(2, Height - (int)textSize.Height - 3, (int)textSize.Width, (int)textSize.Height);
                        break;
                    case ContentAlignment.BottomRight:
                        textRect = new Rectangle(ButtonRect.Width - (int)textSize.Width - 3, Height - (int)textSize.Height - 3, (int)textSize.Width, (int)textSize.Height);
                        break;
                    case ContentAlignment.MiddleCenter:
                        textRect = new Rectangle((ButtonRect.Width - (int)textSize.Width) / 2, (Height - (int)textSize.Height) / 2, (int)textSize.Width, (int)textSize.Height);
                        break;
                    case ContentAlignment.MiddleLeft:
                        textRect = new Rectangle(2, (Height - (int)textSize.Height) / 2, (int)textSize.Width, (int)textSize.Height);
                        break;
                    case ContentAlignment.MiddleRight:
                        textRect = new Rectangle(ButtonRect.Width - (int)textSize.Width - 3, (Height - (int)textSize.Height) / 2, (int)textSize.Width, (int)textSize.Height);
                        break;
                    case ContentAlignment.TopCenter:
                        textRect = new Rectangle((ButtonRect.Width - (int)textSize.Width) / 2, 2, (int)textSize.Width, (int)textSize.Height);
                        break;
                    case ContentAlignment.TopLeft:
                        textRect = new Rectangle(2, 2, (int)textSize.Width, (int)textSize.Height);
                        break;
                    case ContentAlignment.TopRight:
                        textRect = new Rectangle(ButtonRect.Width - (int)textSize.Width - 3, 2, (int)textSize.Width, (int)textSize.Height);
                        break;
                }
                if (PressOffset && ControlState == ControlState.Pressed && CurrentMousePosition == ButtonMousePosition.Button)
                {
                    textRect.X += 1;
                    textRect.Y += 1;
                }
                if (RightToLeft == RightToLeft.Yes)
                {
                    textRect.X = ButtonRect.Width - textRect.Right;
                }
                return;
            }
            if (this.Text == "")
            {
                switch (ImageAlign)
                {
                    case ContentAlignment.BottomCenter:
                        imageRect = new Rectangle((ButtonRect.Width - ImageWidth) / 2, Height - ImageHeight - 3, ImageWidth, ImageHeight);
                        break;
                    case ContentAlignment.BottomLeft:
                        imageRect = new Rectangle(2, Height - ImageHeight - 3, ImageWidth, ImageHeight);
                        break;
                    case ContentAlignment.BottomRight:
                        imageRect = new Rectangle(ButtonRect.Width - ImageWidth - 3, Height - ImageHeight - 3, ImageWidth, ImageHeight);
                        break;
                    case ContentAlignment.MiddleCenter:
                        imageRect = new Rectangle((ButtonRect.Width - ImageWidth) / 2, (Height - ImageHeight) / 2, ImageWidth, ImageHeight);
                        break;
                    case ContentAlignment.MiddleLeft:
                        imageRect = new Rectangle(2, (Height - ImageHeight) / 2, ImageWidth, ImageHeight);
                        break;
                    case ContentAlignment.MiddleRight:
                        imageRect = new Rectangle(ButtonRect.Width - ImageWidth - 3, (Height - ImageHeight) / 2, ImageWidth, ImageHeight);
                        break;
                    case ContentAlignment.TopCenter:
                        imageRect = new Rectangle((ButtonRect.Width - ImageWidth) / 2, 2, ImageWidth, ImageHeight);
                        break;
                    case ContentAlignment.TopLeft:
                        imageRect = new Rectangle(2, 2, ImageWidth, ImageHeight);
                        break;
                    case ContentAlignment.TopRight:
                        imageRect = new Rectangle(ButtonRect.Width - ImageWidth - 3, 2, ImageWidth, ImageHeight);
                        break;
                }
                if (PressOffset && ControlState == ControlState.Pressed && CurrentMousePosition == ButtonMousePosition.Button)
                {
                    imageRect.X += 1;
                    imageRect.Y += 1;
                }
                if (RightToLeft == RightToLeft.Yes)
                {
                    imageRect.X = ButtonRect.Width - imageRect.Right;
                }
                return;
            }
            switch (TextImageRelation)
            {
                case TextImageRelation.Overlay:
                    imageRect = new Rectangle(
                        (ButtonRect.Width - ImageWidth - (int)textSize.Width - ImageTextSpace) / 2,
                        (Height - ImageHeight) / 2,
                        ImageWidth,
                        ImageHeight);
                    textRect = new Rectangle(
                        imageRect.Right + ImageTextSpace,
                        (Height - (int)textSize.Height) / 2,
                        (int)textSize.Width,
                        (int)textSize.Height);
                    break;
                case TextImageRelation.ImageAboveText:
                    imageRect = new Rectangle(
                        (ButtonRect.Width - ImageWidth) / 2,
                        (Height - ImageHeight - (int)textSize.Height - ImageTextSpace) / 2,
                        ImageWidth,
                        ImageHeight);
                    textRect = new Rectangle(
                        (ButtonRect.Width - (int)textSize.Width) / 2,
                        imageRect.Bottom + ImageTextSpace,
                        (int)textSize.Width,
                        (int)textSize.Height);
                    break;
                case TextImageRelation.ImageBeforeText:
                    imageRect = new Rectangle(
                        (ButtonRect.Width - ImageWidth - (int)textSize.Width - ImageTextSpace) / 2,
                        (Height - ImageHeight) / 2,
                        ImageWidth,
                        ImageHeight);
                    textRect = new Rectangle(
                        imageRect.Right + ImageTextSpace,
                        (Height - (int)textSize.Height) / 2,
                        (int)textSize.Width,
                        (int)textSize.Height);
                    break;
                case TextImageRelation.TextAboveImage:
                    textRect = new Rectangle(
                        (ButtonRect.Width - (int)textSize.Width) / 2,
                        (Height - (int)textSize.Height - ImageHeight - ImageTextSpace) / 2,
                        (int)textSize.Width,
                        (int)textSize.Height);
                    imageRect = new Rectangle(
                        (ButtonRect.Width - ImageWidth) / 2,
                        textRect.Bottom + ImageTextSpace,
                        ImageWidth,
                        ImageHeight);
                    break;
                case TextImageRelation.TextBeforeImage:
                    textRect = new Rectangle(
                        (ButtonRect.Width - ImageWidth - (int)textSize.Width - ImageTextSpace) / 2,
                        (Height - (int)textSize.Height) / 2,
                        (int)textSize.Width,
                        (int)textSize.Height);
                    imageRect = new Rectangle(
                        textRect.Right + ImageTextSpace,
                        (Height - ImageHeight) / 2,
                        ImageWidth,
                        ImageHeight);
                    break;
            }
            if (PressOffset && ControlState == ControlState.Pressed && CurrentMousePosition == ButtonMousePosition.Button)
            {
                imageRect.X += 1;
                imageRect.Y += 1;
                textRect.X += 1;
                textRect.Y += 1;
            }

            if (RightToLeft == RightToLeft.Yes)
            {
                imageRect.X = ButtonRect.Width - imageRect.Right;
                textRect.X = ButtonRect.Width - textRect.Right;
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="e"></param>
        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);
            base.OnPaintBackground(e);

            Graphics g = e.Graphics;
            //Rectangle imageRect;//图像区域
            //Rectangle textRect;//文字区域

            this.CalculateRect(out Rectangle imageRect, out Rectangle textRect, g);

            g.SmoothingMode = SmoothingMode.AntiAlias;

            Color baseColor;
            Color borderColor;
            Color innerBorderColor = this.BaseColor;//Color.FromArgb(200, 255, 255, 255); ;

            if (Enabled)
            {
                switch (ControlState)
                {
                    case ControlState.Hover:
                        baseColor = GetColor(BaseColor, 0, -35, -24, -30);
                        borderColor = BaseColor;
                        break;
                    case ControlState.Pressed:
                        baseColor = GetColor(BaseColor, 0, -35, -24, -9);
                        borderColor = BaseColor;
                        break;
                    default:
                        baseColor = BaseColor;
                        borderColor = BaseColor;
                        break;
                }
            }
            else
            {
                baseColor = SystemColors.ControlDark;
                borderColor = SystemColors.ControlDark;
            }

            this.RenderBackgroundInternal(
                g,
                ClientRectangle,
                baseColor,
                borderColor,
                innerBorderColor,
                RoundStyle,
                Radius,
                0.35f,
                false,
                true,
                LinearGradientMode.Vertical);

            if (Image != null)
            {
                g.InterpolationMode = InterpolationMode.HighQualityBilinear;
                g.DrawImage(Image, imageRect, 0, 0, Image.Width, Image.Height, GraphicsUnit.Pixel);
            }
            TextRenderer.DrawText(g, Text, Font, textRect, ForeColor, GetTextFormatFlags(TextAlign, RightToLeft == RightToLeft.Yes));
        }


        private Color GetColor(Color colorBase, int a, int r, int g, int b)
        {
            int a0 = colorBase.A;
            int r0 = colorBase.R;
            int g0 = colorBase.G;
            int b0 = colorBase.B;
            if (a + a0 > 255) { a = 255; } else { a = Math.Max(a + a0, 0); }
            if (r + r0 > 255) { r = 255; } else { r = Math.Max(r + r0, 0); }
            if (g + g0 > 255) { g = 255; } else { g = Math.Max(g + g0, 0); }
            if (b + b0 > 255) { b = 255; } else { b = Math.Max(b + b0, 0); }

            return Color.FromArgb(a, r, g, b);
        }


        internal void RenderBackgroundInternal(
               Graphics g,
               Rectangle rect,
               Color baseColor,
               Color borderColor,
               Color innerBorderColor,
               RoundStyle style,
               int roundWidth,//圆角半径
               float basePosition,
               bool drawBorder,
               bool drawGlass,
               LinearGradientMode mode)
        {
            if (drawBorder)//是否画边框
            {
                rect.Width--;
                rect.Height--;
            }

            using (LinearGradientBrush brush = new LinearGradientBrush(rect, Color.Transparent, Color.Transparent, mode))
            {
                Color[] colors = new Color[4];
                if (ColorGradient)
                {
                    colors[0] = GetColor(baseColor, 0, 35, 24, 9);
                    colors[1] = GetColor(baseColor, 0, 0, 0, 0);
                    colors[2] = baseColor;
                    colors[3] = GetColor(baseColor, 0, 0, 0, 0);
                }
                else
                {
                    colors[0] = baseColor;
                    colors[1] = baseColor;
                    colors[2] = baseColor;
                    colors[3] = baseColor;
                }
                ColorBlend blend = new ColorBlend()
                {
                   Positions = new float[] { 0.0f, basePosition, basePosition, 1.0f },
                   Colors = colors
                };
                brush.InterpolationColors = blend;
                if (style != RoundStyle.None)
                {
                    using (GraphicsPath path =
                        Drawing.CreatePath(rect, roundWidth, style, false))
                    {
                        g.FillPath(brush, path);
                    }

                    if (baseColor.A > 80)
                    {
                        Rectangle rectTop = rect;

                        if (mode == LinearGradientMode.Vertical)
                        {
                            // rectTop.Height = (int)(rectTop.Height * basePosition);
                        }
                        else
                        {
                            // rectTop.Width = (int)(rect.Width * basePosition);
                        }
                        using (GraphicsPath pathTop = Drawing.CreatePath(
                            rectTop, roundWidth, style, false))
                        {
                            if (ColorGradient)
                            {
                                using (SolidBrush brushAlpha =
                                    new SolidBrush(Color.FromArgb(80, 255, 255, 255)))
                                {
                                    g.FillPath(brushAlpha, pathTop);
                                }
                            }
                        }
                    }

                }
            }
        }
        internal static TextFormatFlags GetTextFormatFlags(
            ContentAlignment alignment,
            bool rightToleft)
        {
            TextFormatFlags flags = TextFormatFlags.WordBreak |
                TextFormatFlags.SingleLine;
            if (rightToleft)
            {
                flags |= TextFormatFlags.RightToLeft | TextFormatFlags.Right;
            }

            switch (alignment)
            {
                case ContentAlignment.BottomCenter:
                    flags |= TextFormatFlags.Bottom | TextFormatFlags.HorizontalCenter;
                    break;
                case ContentAlignment.BottomLeft:
                    flags |= TextFormatFlags.Bottom | TextFormatFlags.Left;
                    break;
                case ContentAlignment.BottomRight:
                    flags |= TextFormatFlags.Bottom | TextFormatFlags.Right;
                    break;
                case ContentAlignment.MiddleCenter:
                    flags |= TextFormatFlags.HorizontalCenter |
                        TextFormatFlags.VerticalCenter;
                    break;
                case ContentAlignment.MiddleLeft:
                    flags |= TextFormatFlags.VerticalCenter | TextFormatFlags.Left;
                    break;
                case ContentAlignment.MiddleRight:
                    flags |= TextFormatFlags.VerticalCenter | TextFormatFlags.Right;
                    break;
                case ContentAlignment.TopCenter:
                    flags |= TextFormatFlags.Top | TextFormatFlags.HorizontalCenter;
                    break;
                case ContentAlignment.TopLeft:
                    flags |= TextFormatFlags.Top | TextFormatFlags.Left;
                    break;
                case ContentAlignment.TopRight:
                    flags |= TextFormatFlags.Top | TextFormatFlags.Right;
                    break;
            }
            return flags;
        }
    }
}
