FlatCombo.cs 11.8 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;

namespace Asa.Theme
{
    /// <summary>
    /// 下拉框
    /// </summary>
    [DefaultValue("Text")]
    [DefaultEvent("SelectedIndexChanged")]
    public partial class FlatCombo : FlatBase
    {
        private TextBox _txt;
        private int tick;
        private int index;
        private bool textOver;
        private bool pullOver;
        private bool pull;
        private Rectangle _rect;
        private Rectangle _pullRect;
        private RectangleF _pullStrRect;
        private RectangleF _textRect = new RectangleF();
        private ContentAlignment _textAlign = ContentAlignment.MiddleCenter;

        private const int BORDER_W = 2;
        private const string PULL_STR = "▼";
        private const int ITEM_HEIGHT = 100;

        private FlatList lst = new FlatList();


        /// <summary>
        /// 下拉框
        /// </summary>
        public FlatCombo()
        {
            InitializeComponent();
            _txt = new TextBox();
            //_txt.BackColor = Common.BACK_COLOR;
            _txt.ForeColor = Color.Black;
            _txt.BorderStyle = BorderStyle.None;
            _txt.Visible = false;
            _txt.LostFocus += _txt_LostFocus;
            _txt.TextChanged += _txt_TextChanged;
            _txt.KeyPress += _txt_KeyPress;
            this.Controls.Add(_txt);

            lst.Visible = false;
            lst.BackColor = Common.BACK_COLOR;
            lst.ForeColor = Common.FORE_COLOR;
            lst.Height = ITEM_HEIGHT;
            lst.LostFocus += Lst_LostFocus;
            lst.SelectedIndexChanged += Lst_SelectedIndexChanged;
        }







        /// <summary>
        /// 列表的总数
        /// </summary>
        [Browsable(false)]
        public int Count
        {
            get
            {
                return lst.Count;
            }
        }

        /// <summary>
        /// 显示的文本
        /// </summary>
        [Browsable(true), Category("外观"), Description("显示的文本"), DefaultValue("")]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        public override string Text
        {
            get => base.Text;
            set
            {
                base.Text = value;
                index = Array.FindIndex(lst.Items(), s => s == value);
                CalcSize();
                Refresh();
                SelectedIndexChanged?.Invoke(this);
            }
        }

        /// <summary>
        /// 显示的文本的对齐方式
        /// </summary>
        [Browsable(true), Category(""), Description("显示的文本的对齐方式"), DefaultValue(ContentAlignment.MiddleCenter)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        public ContentAlignment TextAlign
        {
            set
            {
                _textAlign = value;
                CalcSize();
                Refresh();
            }
            get
            {
                return _textAlign;
            }
        }

        /// <summary>
        /// 文本的字体
        /// </summary>
        [Browsable(true), Category("外观"), Description("文本的字体")]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        public override Font Font
        {
            get => base.Font;
            set
            {
                base.Font = value;
                CalcSize();
                Refresh();
            }
        }

        /// <summary>
        /// 选中项的索引
        /// </summary>
        [Browsable(false)]
        public int SelectedIndex
        {
            set
            {
                if (value >= lst.Count || value < 0)
                    index = -1;
                else
                {
                    index = value;
                    Text = lst.Items()[index];
                }
            }
            get
            {
                return index;
            }
        }

        /// <summary>
        /// SelectedIndex改变时发生
        /// </summary>
        [Browsable(true), Category(""), Description("SelectedIndex改变时发生")]
        public event Event.SelectedIndexChanged SelectedIndexChanged;



        /// <summary>
        /// 设置是否可见
        /// </summary>
        public override void SetVisible()
        {
            VisibleItem(false);
        }

        /// <summary>
        /// 计算大小
        /// </summary>
        protected override void CalcSize()
        {
            //Txt.Left = 4;
            //Txt.Top = (Height - Txt.Height) / 2 + 2;  //+2是字符在文本框中偏上
            //Txt.Width = Width - Common.RBUTTON_W - BORDER_W * 3 - 4;


            Graphics g = CreateGraphics();

            _rect = new Rectangle(BORDER_W / 2, BORDER_W / 2, Width - BORDER_W, Height - BORDER_W);
            SizeF sf = g.MeasureString(PULL_STR, Common.FONT_SONG_9);
            _pullRect = new Rectangle(Width - Common.RBUTTON_W - BORDER_W, BORDER_W, Common.RBUTTON_W, Height - BORDER_W - BORDER_W);
            _pullStrRect = new RectangleF(_pullRect.X + (Common.RBUTTON_W - sf.Width) / 2f, _pullRect.Y + (_pullRect.Height - sf.Height) / 2f, sf.Width, sf.Height);

            sf = g.MeasureString(Text, Font);
            switch (TextAlign)
            {
                case ContentAlignment.TopLeft:
                    _textRect = new RectangleF(BORDER_W, BORDER_W, sf.Width, sf.Height);
                    break;
                case ContentAlignment.TopCenter:
                    _textRect = new RectangleF((Width - sf.Width - Common.RBUTTON_W) / 2f, BORDER_W, sf.Width, sf.Height);
                    break;
                case ContentAlignment.TopRight:
                    _textRect = new RectangleF(Width - BORDER_W - sf.Width - Common.RBUTTON_W, BORDER_W, sf.Width, sf.Height);
                    break;
                case ContentAlignment.MiddleLeft:
                    _textRect = new RectangleF(BORDER_W, (Height - sf.Height) / 2f, sf.Width, sf.Height);
                    break;
                case ContentAlignment.MiddleCenter:
                    _textRect = new RectangleF((Width - sf.Width - Common.RBUTTON_W) / 2f, (Height - sf.Height) / 2f, sf.Width, sf.Height);
                    break;
                case ContentAlignment.MiddleRight:
                    _textRect = new RectangleF(Width - BORDER_W - sf.Width - Common.RBUTTON_W, (Height - sf.Height) / 2f, sf.Width, sf.Height);
                    break;
                case ContentAlignment.BottomLeft:
                    _textRect = new RectangleF(BORDER_W, Height - BORDER_W - sf.Height, sf.Width, sf.Height);
                    break;
                case ContentAlignment.BottomCenter:
                    _textRect = new RectangleF((Width - sf.Width - Common.RBUTTON_W) / 2f, Height - BORDER_W - sf.Height, sf.Width, sf.Height);
                    break;
                case ContentAlignment.BottomRight:
                    _textRect = new RectangleF(Width - BORDER_W - sf.Width - Common.RBUTTON_W, Height - BORDER_W - sf.Height, sf.Width, sf.Height);
                    break;
            }
        }



        /// <summary>
        /// 列表添加
        /// </summary>
        /// <param name="s"></param>
        public void ItemAdd(params string[] s)
        {
            lst.ItemAdd(s);
            CalcSize();
            Refresh();
        }

        /// <summary>
        /// 清除列表
        /// </summary>
        public void Clear()
        {
            base.Text = "";
            lst.ItemClear();
            CalcSize();
            Refresh();
        }

        private void VisibleItem(bool visible)
        {
            if (visible)
            {
                lst.Left = Left;
                lst.Top = Top + Height;
                lst.Width = Width;
                pull = true;
                Refresh();
                Parent.Controls.Add(lst);
                lst.Visible = true;
                lst.BringToFront();
                lst.Focus();
            }
            else
            {
                Parent.Controls.Remove(lst);
                lst.Visible = false;
                _txt.Visible = false;
                pull = false;
                Refresh();
            }
        }

        //private void Txt_SizeChanged(object sender, EventArgs e)
        //{
        //    CalcSize();
        //}

        //private void Txt_MouseEnter(object sender, EventArgs e)
        //{
        //    Inside = true;
        //    Refresh();
        //}






        private void FlatCombo_Paint(object sender, PaintEventArgs e)
        {
            e.Graphics.Clear(Common.BACK_COLOR);
            if (pull)  //下拉
            {
                e.Graphics.FillRectangle(Common.BLUE_BRUSH, _pullRect);
                e.Graphics.DrawRectangle(Common.BLUE_PEN, _rect);
                e.Graphics.DrawLine(Common.BLUE_PEN, _pullRect.X, _pullRect.Y, _pullRect.X, _pullRect.Bottom);
            }
            else if (Inside)
            {
                if (pullOver)
                    e.Graphics.FillRectangle(Common.OVER_BRUSH, _pullRect);
                e.Graphics.DrawRectangle(Common.BLUE_PEN, _rect);
                e.Graphics.DrawLine(Common.BLUE_PEN, _pullRect.X, _pullRect.Y, _pullRect.X, _pullRect.Bottom);
            }
            else
            {
                e.Graphics.DrawRectangle(Common.BORDER_PEN, _rect);
            }
            e.Graphics.DrawString(Text, Font, Common.FORE_BRUSH, _textRect);
            e.Graphics.DrawString(PULL_STR, Common.FONT_SONG_9, Common.FORE_BRUSH, _pullStrRect);
        }

        private void FlatCombo_MouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button != MouseButtons.Left) return;

            if (pullOver)
            {
                if (Environment.TickCount - tick < 100) return;
                if (pull)
                {
                    VisibleItem(false);
                }
                else
                {
                    if (Parent is FlatForm)
                    {
                        ((FlatForm)Parent).SetVisible(this);
                    }
                    VisibleItem(true);
                }
            }
            else
            {
                if (e.X < Width - Common.RBUTTON_W)
                {
                    _txt.Left = 0;
                    _txt.Top = (Height - _txt.Height) / 2;
                    _txt.Width = Width - Common.RBUTTON_W;
                    _txt.Text = Text;
                    _txt.Visible = true;
                    _txt.Focus();
                }
            }
        }

        private void FlatCombo_MouseUp(object sender, MouseEventArgs e)
        {

        }

        private void FlatCombo_MouseMove(object sender, MouseEventArgs e)
        {
            bool bln;
            if (_pullRect.Contains(e.Location))
                bln = true;
            else
                bln = false;

            if (bln != pullOver)
            {
                pullOver = bln;
                Refresh();
            }
        }

        private void Lst_LostFocus(object sender, EventArgs e)
        {
            tick = Environment.TickCount;
            VisibleItem(false);
        }

        private void Lst_SelectedIndexChanged(object sender)
        {
            Text = lst.Text;
            VisibleItem(false);
            index = lst.SelectedIndex;
            SelectedIndexChanged?.Invoke(this);
        }

        private void _txt_LostFocus(object sender, EventArgs e)
        {
            tick = Environment.TickCount;
            VisibleItem(false);
        }

        private void _txt_TextChanged(object sender, EventArgs e)
        {
            Text = _txt.Text;
        }

        private void _txt_KeyPress(object sender, KeyPressEventArgs e)
        {
           
        }
    }
}