// == LICENSE INFORMATION ==
/*
 * First author tiritomato 2013.
 * This program is distributed under the GNU Lesser General Public License(LGPL ver3).
 * support blog (Japanese only) http://d.hatena.ne.jp/tiri_tomato/
 */
// == LICENSE INFORMATION ==

using System;
using System.Drawing;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace DotNetEx.CustomControls
{
    //! @addtogroup DotNetEx-CustomControls名前空間
    //! @{

    //! @brief プルダウンのサイズ調整に対応したコンボボックス
    public partial class ComboBox : System.Windows.Forms.ComboBox
    {
        public enum DropDownWidthMode
        {
            None,
            AutoWidthOnDropDown,
            AutoWidthOnHandleCreateAndDestroy
        }
        
        [DllImport("user32.dll")]
        static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);

        [System.ComponentModel.DefaultValue(DropDownWidthMode.AutoWidthOnDropDown)]
        [System.ComponentModel.Description("trueに設定するとDropDownWidthを自動調整します。ComboBox.Widthより小さくは設定できません。")]
        public DropDownWidthMode DropDownAutoWidth { get; set; }
        
        public ComboBox()
        {
            DropDownAutoWidth = DropDownWidthMode.AutoWidthOnDropDown;
            InitializeComponent();
        }

        // protected implement //

        protected override void OnDropDown(EventArgs e)
        {
            if (DropDownAutoWidth == DropDownWidthMode.AutoWidthOnDropDown) UpdateDropDownWidth();
            base.OnDropDown(e);
        }

        protected override void OnHandleCreated(EventArgs e)
        {
            base.OnHandleCreated(e);
            if (DropDownAutoWidth == DropDownWidthMode.AutoWidthOnHandleCreateAndDestroy) UpdateDropDownWidth();
        }

        protected override void OnHandleDestroyed(EventArgs e)
        {
            base.OnHandleDestroyed(e);
            if (DropDownAutoWidth == DropDownWidthMode.AutoWidthOnHandleCreateAndDestroy) UpdateDropDownWidth();
        }

        protected override void WndProc(ref Message m)
        {
            if ((DropDownAutoWidth != DropDownWidthMode.None) && (m.Msg == WM_CTLCOLORLISTBOX))
            {
                int left = this.PointToScreen(new Point(0, 0)).X;

                if (this.DropDownWidth > Screen.PrimaryScreen.WorkingArea.Width - left)
                {
                    Rectangle comboRect = this.RectangleToScreen(this.ClientRectangle);

                    int dropHeight = 0;
                    int topOfDropDown = 0;
                    int leftOfDropDown = 0;

                    for (int i = 0; (i < this.Items.Count && i < this.MaxDropDownItems); i++) dropHeight += this.ItemHeight;

                    if (dropHeight > Screen.PrimaryScreen.WorkingArea.Height - this.PointToScreen(new Point(0, 0)).Y)
                    {
                        topOfDropDown = comboRect.Top - dropHeight - 2;
                    }
                    else
                    {
                        topOfDropDown = comboRect.Bottom;
                    }

                    leftOfDropDown = comboRect.Left - (this.DropDownWidth - (Screen.PrimaryScreen.WorkingArea.Width - left));
                    SetWindowPos(m.LParam, IntPtr.Zero, leftOfDropDown, topOfDropDown, 0, 0, SWP_NOSIZE);
                }
            }

            base.WndProc(ref m);
        }

        // private implement //
        private const int SWP_NOSIZE = 0x1;
        private const UInt32 WM_CTLCOLORLISTBOX = 0x0134;
        private void UpdateDropDownWidth()
        {
            using (System.Drawing.Graphics ds = CreateGraphics())
            {
                float maxWidth = 0;
                foreach (System.Object item in this.Items) maxWidth = Math.Max(maxWidth, ds.MeasureString(item.ToString(), this.Font).Width);
                if (MaxDropDownItems < Items.Count) maxWidth += SystemInformation.VerticalScrollBarWidth;
                int newWidth = Math.Min((int)Decimal.Round((decimal)maxWidth, 0), Screen.GetWorkingArea(this).Width);
                if (newWidth > Width) this.DropDownWidth = newWidth;
            }
        }
    }

    //! @}
}