/*
 * 本代码受中华人民共和国著作权法保护，作者仅授权下载代码之人在学习和交流范围内
 * 自由使用与修改代码；欲将代码用于商业用途的，请先与作者联系。
 * 使用本代码请保留此处信息。作者联系方式：ping3108@163.com, 欢迎进行技术交流
 */

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
using System.Runtime.InteropServices;

using MGdu.WinFormUI;
using MGdu.WinFormUI.MyGraphics;
using System.Security.Permissions;

namespace MGdu.WinFormUI
{
    /// <summary>
    /// a form that supports custom theme
    /// </summary>
    [PermissionSet(SecurityAction.Demand, Name = "FullTrust")]
    [System.Runtime.InteropServices.ComVisibleAttribute(true)]
    public partial class GMForm : Form
    {

        #region private variable

        ControlBoxManager controlBoxManager;
        GMShadow _shawdowForm;
       // Form _lastClosedMdiChild;
        List<Form> _listClosedMdiChild;
        MdiBarController _mdiBarController;

        #endregion

        #region mdi event support

        EventHandler _mdiNewTabButtonClick;
        EventHandler _mdiTabCloseButtonClick;
        EventHandler _mdiBarCreated;
        /// <summary>
        /// 标签新建按钮事件
        /// </summary>
        [Description("标签新建按钮事件")]

        public event EventHandler MdiNewTabButtonClick
        {
            add
            {
                _mdiNewTabButtonClick = value;
            }
            remove
            {
                _mdiNewTabButtonClick = null;
            }
        }
        /// <summary>
        /// 标签关闭按钮事件
        /// </summary>
        [Description("标签关闭按钮事件")]

        public event EventHandler MdiTabCloseButtonClick
        {
            add
            {
                _mdiTabCloseButtonClick = value;
            }
            remove
            {
                _mdiTabCloseButtonClick = null;
            }
        }
        /// <summary>
        ///标签创建时事件
        /// </summary>
        [Description("标签创建时事件")]

        public event EventHandler MdiBarCreated
        {
            add { _mdiBarCreated = value; }
            remove { _mdiBarCreated = null; }
        }

        private void OnMdiNewTabButtonClick(object sender, EventArgs e)
        {
            _mdiNewTabButtonClick?.Invoke(sender, e);
        }

        private void OnMdiTabCloseButtonClick(object sender, EventArgs e)
        {
            _mdiTabCloseButtonClick?.Invoke(sender, e);
        }
        /// <summary>
        /// 在标签栏创建时激发
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected virtual void OnMdiBarCreated(object sender, EventArgs e)
        {
            _mdiBarCreated?.Invoke(sender, e);
        }

        #endregion

        #region property

        #region property private var

        bool _resizable = true;             // not with theme
        Padding _padding = new Padding(0);  // not with theme

        ThemeFormBase _myTheme;

        #endregion
        /// <summary>
        /// 内边距
        /// </summary>

        [DefaultValue(typeof(Padding), "0")]
        public new Padding Padding
        {
            get { return _padding; }
            set
            {
                _padding = value;
                base.Padding = new Padding(
                    BorderWidth + _padding.Left,
                    CaptionHeight + BorderWidth + _padding.Top,
                    BorderWidth + _padding.Right,
                    BorderWidth + _padding.Bottom);
            }
        }
        /// <summary>
        /// 默认内边距
        /// </summary>
        protected override Padding DefaultPadding
        {
            get
            {
                return new Padding(
                    BorderWidth,
                    BorderWidth + CaptionHeight,
                    BorderWidth,
                    BorderWidth);
            }
        }
        /// <summary>
        /// 标题
        /// </summary>
        public override string Text
        {
            get
            {
                return base.Text;
            }
            set
            {
                base.Text = value;
                Invalidate(TextRect);
            }
        }
        /// <summary>
        /// 皮肤/主题
        /// </summary>
        [Browsable(false)]
        public ThemeFormBase XTheme
        {
            get
            {
                if (_myTheme == null)
                    _myTheme = new ThemeFormBase();
                return _myTheme;
            }
            set
            {
                _myTheme = value;
                PrepareForNewTheme();
                Invalidate();
            }
        }

        #region editable gmform properties
        /// <summary>
        /// 是否可拖动改变窗体大小
        /// </summary>
        [Category("GMForm")]
        [Description("是否可拖动改变窗体大小")]
        [DefaultValue(true)]
        public bool Resizable
        {
            get { return _resizable; }
            set
            {
                _resizable = value;
            }
        }
        /// <summary>
        /// 窗体边界大小，鼠标移动到该边界将变成指针形状，拖动可改变窗体大小
        /// </summary>
        [Category("GMForm")]
        [Description("窗体边界大小，鼠标移动到该边界将变成指针形状，拖动可改变窗体大小")]
        [DefaultValue(6)]
        public int SideResizeWidth
        {
            get { return XTheme.SideResizeWidth; }
            set
            {
                if (value != XTheme.SideResizeWidth)
                {
                    XTheme.SideResizeWidth = value;
                }
            }
        }
        /// <summary>
        /// 窗体边框大小
        /// </summary>
        [Category("GMForm")]
        [Description("窗体边框大小")]
        [DefaultValue(6)]
        public int BorderWidth
        {
            get { return XTheme.BorderWidth; }
            set
            {
                if (value != XTheme.BorderWidth)
                {
                    XTheme.BorderWidth = value;
                    Invalidate();
                }
            }
        }
        /// <summary>
        /// 标题栏高度
        /// </summary>
        [Category("GMForm")]
        [Description("标题栏高度")]
        [DefaultValue(30)]
        public int CaptionHeight
        {
            get { return XTheme.CaptionHeight; }
            set
            {
                if (value != XTheme.CaptionHeight)
                {
                    XTheme.CaptionHeight = value;
                    Invalidate();
                }
            }
        }
        /// <summary>
        ///窗体圆角程度 
        /// </summary>
        [Category("GMForm")]
        [DefaultValue(8)]
        [Description("窗体圆角程度")]
        public int Radius
        {
            get { return XTheme.Radius; }
            set
            {
                if (value != XTheme.Radius)
                {
                    XTheme.Radius = (value < 0 ? 0 : value);
                    Invalidate();
                }
            }
        }
        /// <summary>
        /// 窗体圆角样式
        /// </summary>
        [Category("GMForm")]
        [DefaultValue(typeof(RoundStyle), "2")]
        [Description("窗体圆角样式")]
        public RoundStyle Round
        {
            get { return XTheme.RoundedStyle; }
            set
            {
                if (value != XTheme.RoundedStyle)
                {
                    XTheme.RoundedStyle = value;
                    Invalidate();
                }
            }
        }
        /// <summary>
        /// 控制按钮相对于右上角的偏移量
        /// </summary>
        [Category("GMForm")]
        [Description("控制按钮相对于右上角的偏移量")]
        [DefaultValue(typeof(Point), "8, 8")]
        public Point ControlBoxOffset
        {
            get { return XTheme.ControlBoxOffset; }
            set
            {
                XTheme.ControlBoxOffset = value;
                Invalidate();
            }
        }
        /// <summary>
        /// 关闭/最大化/最小化按钮之间的距离，可以设置成负值使它们重叠
        /// </summary>
        [Category("GMForm")]
        [Description("关闭/最大化/最小化按钮之间的距离，可以设置成负值使它们重叠")]
        [DefaultValue(0)]
        public int ControlBoxSpace
        {
            get { return XTheme.ControlBoxSpace; }
            set
            {
                XTheme.ControlBoxSpace = value;
                Invalidate();
            }
        }
        /// <summary>
        /// 标题栏图标尺寸
        /// </summary>
        [Category("GMForm")]
        [Description("标题栏图标尺寸")]
        [DefaultValue(typeof(Size), "16,16")]
        public Size IconSize
        {
            get
            {
                if (ShowIcon)
                    return XTheme.IconSize;
                else
                    return System.Drawing.Size.Empty;
            }
            set
            {
                XTheme.IconSize = value;
                Invalidate();
            }
        }
        /// <summary>
        /// 标题栏图标与窗体左边框的距离
        /// </summary>
        [Category("GMForm")]
        [Description("标题栏图标与窗体左边框的距离")]
        [DefaultValue(2)]
        public int IconLeftMargin
        {
            get { return (this.ShowIcon ? XTheme.IconLeftMargin : 0); }
            set
            {
                XTheme.IconLeftMargin = value;
                Invalidate();
            }
        }
        /// <summary>
        /// 标题距离左边的距离
        /// </summary>
        [Category("GMForm")]
        [DefaultValue(2), Description("标题距离左边的距离")]
        public int TextLeftMargin
        {
            get { return XTheme.TextLeftMargin; }
            set
            {
                XTheme.TextLeftMargin = value;
                Invalidate();
            }
        }
        /// <summary>
        /// 窗体关闭按钮的尺寸
        /// </summary>
        [Category("GMForm")]
        [Description("窗体关闭按钮的尺寸")]
        [DefaultValue(typeof(Size), "37, 17")]
        public Size CloseBoxSize
        {
            get { return XTheme.CloseBoxSize; }
            set
            {
                XTheme.CloseBoxSize = value;
                Invalidate();
            }
        }
        /// <summary>
        /// 窗体最大化/还原按钮的大小
        /// </summary>
        [Category("GMForm")]
        [DefaultValue(typeof(Size), "25, 17")]
        [Description("窗体最大化/还原按钮的大小")]
        public Size MaxBoxSize
        {
            get { return XTheme.MaxBoxSize; }
            set
            {
                XTheme.MaxBoxSize = value;
                Invalidate();
            }
        }
        /// <summary>
        /// 窗体最小化按钮的大小
        /// </summary>
        [Category("GMForm")]
        [DefaultValue(typeof(Size), "25, 17")]
        [Description("窗体最小化按钮的大小")]
        public Size MinBoxSize
        {
            get { return XTheme.MinBoxSize; }
            set
            {
                XTheme.MinBoxSize = value;
                Invalidate();
            }
        }

        #endregion

        #region form shadow about
        /// <summary>
        /// 是否显示阴影
        /// </summary>
        [Category("Form Shadow"), Description("是否显示阴影")]
        public bool ShowShadow
        {
            get { return XTheme.ShowShadow; }
            set
            {
                if (value != XTheme.ShowShadow)
                {
                    XTheme.ShowShadow = value;
                }
            }
        }
        /// <summary>
        /// 窗体阴影宽度
        /// </summary>
        [Category("Form Shadow"), Description("窗体阴影宽度")]
        public int ShadowWidth
        {
            get { return XTheme.ShadowWidth; }
            set
            {
                XTheme.ShadowWidth = value;
            }
        }
        /// <summary>
        /// 使用阴影来缩放
        /// </summary>
        [Category("Form Shadow"), Description("使用阴影来缩放")]
        public bool UseShadowToResize
        {
            get { return XTheme.UseShadowToResize; }
            set
            {
                XTheme.UseShadowToResize = value;
            }
        }
        /// <summary>
        /// 窗体阴影颜色
        /// </summary>
        [Category("Form Shadow")]
        [Description("窗体阴影颜色")]
        public Color ShadowColor
        {
            get { return XTheme.ShadowColor; }
            set
            {
                XTheme.ShadowColor = value;
            }
        }
        /// <summary>
        /// 阴影从里到外是逐渐变浅的，这个值设置深色部分的透明度，ARGB中的A值
        /// </summary>
        [Category("Form Shadow")]
        [Description("阴影从里到外是逐渐变浅的，这个值设置深色部分的透明度，ARGB中的A值")]
        public int ShadowAValueDark
        {
            get { return XTheme.ShadowAValueDark; }
            set
            {
                XTheme.ShadowAValueDark = value;
            }
        }
        /// <summary>
        /// 阴影从里到外是逐渐变浅的，这个值设置浅色部分的透明度，ARGB中的A值
        /// </summary>
        [Category("Form Shadow")]
        [Description("阴影从里到外是逐渐变浅的，这个值设置浅色部分的透明度，ARGB中的A值")]
        public int ShadowAValueLight
        {
            get { return XTheme.ShadowAValueLight; }
            set
            {
                XTheme.ShadowAValueLight = value;
            }
        }

        #endregion

        #region form resize region, internal readonly

        internal Rectangle TopLeftRect
        {
            get
            {
                return new Rectangle(0, 0, SideResizeWidth, SideResizeWidth);
            }
        }

        internal Rectangle TopRect
        {
            get
            {
                return new Rectangle(
                    SideResizeWidth,
                    0,
                    this.Size.Width - SideResizeWidth * 2,
                    SideResizeWidth);
            }
        }

        internal Rectangle TopRightRect
        {
            get
            {
                return new Rectangle(
                    this.Size.Width - SideResizeWidth,
                    0,
                    SideResizeWidth,
                    SideResizeWidth);
            }
        }

        internal Rectangle LeftRect
        {
            get
            {
                return new Rectangle(
                    0,
                    SideResizeWidth,
                    SideResizeWidth,
                    this.Size.Height - SideResizeWidth * 2);
            }
        }

        internal Rectangle RightRect
        {
            get
            {
                return new Rectangle(
                    this.Size.Width - SideResizeWidth,
                    SideResizeWidth,
                    SideResizeWidth,
                    this.Size.Height - SideResizeWidth * 2);
            }
        }

        internal Rectangle BottomLeftRect
        {
            get
            {
                return new Rectangle(
                    0,
                    this.Size.Height - SideResizeWidth,
                    SideResizeWidth,
                    SideResizeWidth);
            }
        }

        internal Rectangle BottomRect
        {
            get
            {
                return new Rectangle(
                    SideResizeWidth,
                    this.Size.Height - SideResizeWidth,
                    this.Size.Width - SideResizeWidth * 2,
                    SideResizeWidth);
            }
        }

        internal Rectangle BottomRightRect
        {
            get
            {
                return new Rectangle(
                    this.Size.Width - SideResizeWidth,
                    this.Size.Height - SideResizeWidth,
                    SideResizeWidth,
                    SideResizeWidth);
            }
        }

        #endregion


        #region calculated rect

        internal Rectangle CaptionRect
        {
            get
            {
                return new Rectangle(
                    BorderWidth,
                    BorderWidth,
                    this.ClientSize.Width - BorderWidth * 2,
                    CaptionHeight);
            }
        }

        internal Rectangle CaptionRectToDraw
        {
            get
            {
                return new Rectangle(
                    0,
                    0,
                    this.ClientSize.Width,
                    CaptionHeight + BorderWidth);
            }
        }

        internal Rectangle CloseBoxRect
        {
            get
            {
                if (ControlBox)
                {
                    int x = ClientSize.Width - ControlBoxOffset.X - CloseBoxSize.Width;
                    return new Rectangle(
                        new Point(x, ControlBoxOffset.Y),
                        CloseBoxSize);
                }
                else
                    return Rectangle.Empty;
            }
        }

        internal Rectangle MaxBoxRect
        {
            get
            {
                if (ControlBox && MaximizeBox)
                {
                    int x = CloseBoxRect.Left - ControlBoxSpace - MaxBoxSize.Width;
                    return new Rectangle(
                        new Point(x, ControlBoxOffset.Y),
                        MaxBoxSize);
                }
                else
                    return Rectangle.Empty;
            }
        }

        internal Rectangle MinBoxRect
        {
            get
            {
                if (ControlBox && MinimizeBox)
                {
                    int x;
                    if (MaximizeBox)
                        x = MaxBoxRect.Left - ControlBoxSpace - MinBoxSize.Width;
                    else
                        x = CloseBoxRect.Left - ControlBoxSpace - MinBoxSize.Width;
                    return new Rectangle(
                        new Point(x, ControlBoxOffset.Y),
                        MinBoxSize);
                }
                else
                    return Rectangle.Empty;
            }
        }

        internal Rectangle IconRect
        {
            get
            {
                if (ControlBox && ShowIcon)
                {
                    int x = BorderWidth + IconLeftMargin;
                    int y = BorderWidth + (CaptionHeight - IconSize.Height) / 2;
                    return new Rectangle(new Point(x, y), IconSize);
                }
                else
                    return new Rectangle(BorderWidth, BorderWidth, 0, 0);
            }
        }

        internal Rectangle TextRect
        {
            get
            {
                int x = IconRect.Right + TextLeftMargin;
                int y = BorderWidth;
                int height = CaptionHeight;
                int right = this.ClientSize.Width - x;
                if (ControlBox)
                {
                    right = CloseBoxRect.Left;
                    if (MinimizeBox)
                    {
                        right = MinBoxRect.Left;
                    }
                    else if (MaximizeBox)
                    {
                        right = MaxBoxRect.Left;
                    }
                }
                int width = right - x;
                return new Rectangle(x, y, width, height);
            }
        }

        #endregion

        /// <summary>
        /// 表示去掉自画的边框及标题栏后，剩下的可用的客户区区域，坐标相对于窗体左上角
        /// </summary>
        [Browsable(false)]
        public Rectangle UserClientBounds
        {
            get
            {
                return new Rectangle(
                    BorderWidth,
                    BorderWidth + CaptionHeight,
                    ClientSize.Width - BorderWidth * 2,
                    ClientSize.Height - BorderWidth * 2 - CaptionHeight);
            }
        }

        /// <summary>
        /// 表示去掉自画的边框及标题栏后，剩下的可用的客户区大小
        /// </summary>
        [Browsable(false)]
        public Size UserClientSize
        {
            get
            {
                return new Size(
                    ClientSize.Width - BorderWidth * 2,
                    ClientSize.Height - BorderWidth * 2 - CaptionHeight);
            }
        }

        /// <summary>
        /// 表示MDI标签栏的区域，包括bottom-region
        /// </summary>
        [Browsable(false)]
        public Rectangle MdiBarBounds
        {
            get
            {
                if (!IsMdiContainer || _mdiBarController == null)
                    return Rectangle.Empty;
                return _mdiBarController.Bounds;
            }
        }

        #endregion

        #region constructor & initialize
        /// <summary>
        /// MGdUI皮肤
        /// </summary>
        public GMForm()
            : base()
        {
            InitializeComponent();
            FormIni();
            //if (!DesignMode)
            //{
            //    base.ShowInTaskbar = ShowInTaskbar;
            //}
            // 下面这个条件是永远不为true的，如果不把此类直接设置成mdicontainer
            //if (this.IsMdiContainer)
            //    SetMdiClient();
        }

        private void FormIni()
        {
            this.SetStyle(
                ControlStyles.AllPaintingInWmPaint |
                ControlStyles.UserPaint |
                ControlStyles.OptimizedDoubleBuffer |
                ControlStyles.ResizeRedraw, true);
            this.DoubleBuffered = true;
            this.UpdateStyles();
            base.Padding = DefaultPadding;
            if (ControlBox)
                controlBoxManager = new ControlBoxManager(this);
        }

        #region MDI-Support
        /// <summary>
        /// 获取子窗体
        /// </summary>
        /// <returns></returns>
        public MdiClient GetMdiClient()
        {
            MdiClient mdiclient = null;
            foreach (Control ctl in Controls)
            {
                if ((mdiclient = ctl as MdiClient) != null)
                    break;
            }
            return mdiclient;
        }

        /// <summary>
        /// 通过sendmessage方式激活子窗体以避免闪烁
        /// </summary>
        /// <param name="childToActivate"></param>
        public void ActivateMdiChildForm(Form childToActivate)
        {
            MdiClient mdi = GetMdiClient();
            if (mdi == null)
                return;
            if (base.ActiveMdiChild == childToActivate)
                return;
            if (base.MdiChildren.Length < 2)
                return;
            Control form;
            bool isNext;
            int pos = mdi.Controls.IndexOf(childToActivate);
            if (pos < 0)
                return;
            if (pos == 0)
            {
                form = mdi.Controls[pos + 1];
                isNext = true;
            }
            else
            {
                form = mdi.Controls[pos - 1];
                isNext = false;
            }
            IntPtr next = (isNext ? Win32.WinAPI.TRUE : Win32.WinAPI.FALSE);
            Win32.WinAPI.SendMessage(mdi.Handle,
                (int)Win32.WinAPI.WindowMessages.WM_MDINEXT, form.Handle, next);
        }

        private void SetMdiClient()
        {
            if (!IsMdiContainer)
                return;

            MdiClient mdi = GetMdiClient();
            if (mdi != null)
            {
                SetMdiStyles(mdi);
                UpdateMdiStyles(mdi);
                SetMdiClientLocation(mdi);
            }
        }

        private void SetMdiStyles(MdiClient mdi)
        {
            // remove the border

            int style = Win32.WinAPI.GetWindowLong(mdi.Handle, (int)Win32.WinAPI.GWLPara.GWL_STYLE);
            int exStyle = Win32.WinAPI.GetWindowLong(mdi.Handle, (int)Win32.WinAPI.GWLPara.GWL_EXSTYLE);

            style &= ~(int)Win32.WinAPI.WindowStyle.WS_BORDER;
            exStyle &= ~(int)Win32.WinAPI.WindowStyleEx.WS_EX_CLIENTEDGE;

            Win32.WinAPI.SetWindowLong(mdi.Handle, (int)Win32.WinAPI.GWLPara.GWL_STYLE, style);
            Win32.WinAPI.SetWindowLong(mdi.Handle, (int)Win32.WinAPI.GWLPara.GWL_EXSTYLE, exStyle);

            Win32.WinAPI.ShowScrollBar(mdi.Handle, (int)Win32.WinAPI.ScrollBar.SB_BOTH, 0 /*false*/);
        }

        private void UpdateMdiStyles(MdiClient mdi)
        {
            // To show style changes, the non-client area must be repainted. Using the
            // control's Invalidate method does not affect the non-client area.
            // Instead use a Win32 call to signal the style has changed.

            Win32.WinAPI.SetWindowPos(mdi.Handle, IntPtr.Zero, 0, 0, 0, 0,
                (uint)Win32.WinAPI.SWPPara.SWP_NOACTIVATE |
                (uint)Win32.WinAPI.SWPPara.SWP_NOMOVE |
                (uint)Win32.WinAPI.SWPPara.SWP_NOSIZE |
                (uint)Win32.WinAPI.SWPPara.SWP_NOZORDER |
                (uint)Win32.WinAPI.SWPPara.SWP_NOOWNERZORDER |
                (uint)Win32.WinAPI.SWPPara.SWP_FRAMECHANGED);
        }

        private void SetMdiClientLocation(MdiClient mdi)
        {
            mdi.BackColor = Color.White;
            //mdi.Margin = new Padding(10);
            //mdi.Dock = DockStyle.None;

            //mdi.Location = new Point(30, 40);
            //mdi.Size = new Size(400, 260);

        }

        // used for child mdi form to notify its parent form that it's closed
        /// <summary>
        /// 当子窗体关闭时激发
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void MdiChildClosed(object sender, FormClosedEventArgs e)
        {
            if (sender is Form child)
            {
                //_lastClosedMdiChild = child;
                _listClosedMdiChild.Add(child);
            }
        }

        // for mdi child form
        /// <summary>
        /// 子窗体可视化变化
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void MdiChildVisibleChange(object sender, EventArgs e)
        {
            base.Invalidate();
        }
        /// <summary>
        /// 获取当前的子窗体列表
        /// </summary>
        /// <returns></returns>
        public List<Form> GetCurrentMdiChildren()
        {
            List<Form> list = new List<Form>();
            if (_listClosedMdiChild != null)
            {
                foreach (Form f in MdiChildren)
                {
                    if (!_listClosedMdiChild.Contains(f) && f.Visible)
                        list.Add(f);
                }
            }
            return list;
        }

        #endregion

        #endregion

        #region private method

        private void SetFormMinimizeSize()
        {
            int minW = 160;
            int minH = 60;

            int w = BorderWidth * 2 + IconLeftMargin + IconSize.Width
                + TextLeftMargin + MinBoxSize.Width + MaxBoxSize.Width
                + CloseBoxSize.Width + ControlBoxSpace * 2
                + ControlBoxOffset.X + 12;
            if (w < minW)
                w = minW;
            int h = BorderWidth * 2 + CaptionHeight + 8;
            if (h < minH)
                h = minH;
            base.MinimumSize = new Size(w, h);
        }

        private void SetShadowFormSize()
        {
            if (_shawdowForm == null || _shawdowForm.IsDisposed)
                return;
            if (base.WindowState == FormWindowState.Normal)
            {
                var size = base.Size;
                //if (!this.DesignMode)
                {
                    size.Width += XTheme.ShadowWidth * 2;
                    size.Height += XTheme.ShadowWidth * 2;
                }
                if (_shawdowForm.Size != size)
                {
                    _shawdowForm.Size = size;
                    // update size -- api: movewindow....
                }
            }
        }

        private void SetShadowFormLocation()
        {
            if (_shawdowForm == null || _shawdowForm.IsDisposed)
                return;
            if (base.WindowState == FormWindowState.Normal)
            {
                Point p = base.Location;
                if (!this.DesignMode)
                { p.Offset(-XTheme.ShadowWidth, -XTheme.ShadowWidth); }
                if (_shawdowForm.Location != p)
                {
                    _shawdowForm.Location = p;
                    // update location -- api: movewindow....
                }
            }
        }

        private void PrepareForNewTheme()
        {
            if (base.Region != null)
                base.Region.Dispose();
            base.Region = null;

            if (ControlBox)
            {
                controlBoxManager.ResetBoxColor();
                controlBoxManager.FormResize();
            }
            SetFormRegion();
            //Padding = new Padding(0);
            base.BackColor = XTheme.FormBackColor;
            base.OnSizeChanged(EventArgs.Empty);
            SetFormMinimizeSize();
            if (XTheme.ShowShadow)
            {
                if (_shawdowForm == null || _shawdowForm.IsDisposed)
                {
                    OnActivated(EventArgs.Empty);
                }
            }
            else
            {
                if (_shawdowForm != null)
                {
                    _shawdowForm.Close();
                    _shawdowForm = null;
                }
            }
        }

        private void SetFormRegion()
        {
            //if (this.DesignMode) { return; }
            if (base.Region != null)
                base.Region.Dispose();

            Rectangle rect = new Rectangle(Point.Empty, base.Size);
            GraphicsPath path;

            if (XTheme.UseDefaultTopRoundingFormRegion)
                path = GraphicsPathHelper.CreateTopRoundedPathForFormRegion(rect);
            else
                path = GraphicsPathHelper.CreateRoundedRect(rect, Radius, Round, false);

            this.Region = new Region(path);
        }

        //private GraphicsPath CreateRoundedFormRect(bool correction)
        //{
        //    Rectangle rect = new Rectangle(Point.Empty, this.Size);
        //    return GraphicsPathHelper.CreateRoundedRect(rect, Radius, Round, correction);
        //}

        /// <summary>
        /// 判断所接收到的 wm_nc-calc-size 消息是否指示窗体即将最小化
        /// </summary>        
        private bool IsAboutToMinimize(Win32.WinAPI.RECT rect)
        {
            if (rect.Left == -32000 && rect.Top == -32000)
                return true;
            else
                return false;
        }

        /// <summary>
        /// 判断所接收到的 wm_nc-calc-size 消息是否指示窗体即将最大化
        /// </summary>        
        private bool IsAboutToMaximize(Win32.WinAPI.RECT rect)
        {
            /*
             * 判断的方法是，只要窗体的左右、上下都延伸到了屏幕工作区之外，
             * 并且左和右、上和下都延伸相同的量，就认为窗体是要进行最大化
             */

            int left = rect.Left;
            int top = rect.Top;
            int width = rect.Right - rect.Left;
            int height = rect.Bottom - rect.Top;

            if (left < 0 && top < 0)
            {
                Rectangle workingArea = Screen.GetWorkingArea(this);
                if (width == (workingArea.Width + (-left) * 2)
                    && height == (workingArea.Height + (-top) * 2))
                    return true;
            }
            return false;
        }

        private void DrawFormBackground(Graphics g)
        {
            SmoothingMode oldMode = g.SmoothingMode;
            if (Round != RoundStyle.None)
                g.SmoothingMode = SmoothingMode.AntiAlias;

            using (SolidBrush sb = new SolidBrush(XTheme.FormBackColor))
            {
                using (GraphicsPath path = GraphicsPathHelper.CreateRoundedRect(
                    ClientRectangle, Radius, Round, false))
                {
                    g.FillPath(sb, path);
                }
            }
            g.SmoothingMode = oldMode;
        }

        private void DrawCaptionBackground(Graphics g)
        {
            using (LinearGradientBrush lb = new LinearGradientBrush(
                 CaptionRectToDraw,
                 XTheme.CaptionBackColorTop,
                 XTheme.CaptionBackColorBottom,
                 LinearGradientMode.Vertical))
            {
                g.FillRectangle(lb, CaptionRectToDraw);
            }
        }

        private void DrawFormIconAndText(Graphics g)
        {
            if (ShowIcon && Icon != null && XTheme.DrawCaptionIcon)
            {
                g.DrawIcon(this.Icon, IconRect);
            }

            if (!string.IsNullOrEmpty(Text) && XTheme.DrawCaptionText)
            {
                TextRenderer.DrawText(
                    g,
                    this.Text,
                    SystemFonts.CaptionFont,
                    TextRect,
                    XTheme.CaptionTextColor,
                    (XTheme.CaptionTextCenter ? TextFormatFlags.HorizontalCenter : TextFormatFlags.Left) |
                    TextFormatFlags.VerticalCenter |
                    TextFormatFlags.EndEllipsis);
            }
        }

        private void DrawFormBorder(Graphics g)
        {
            //if (this.DesignMode) { return; }
            int width = BorderWidth;
            Rectangle rect = ClientRectangle;

            SmoothingMode oldMode = g.SmoothingMode;
            if (Round != RoundStyle.None)
                g.SmoothingMode = SmoothingMode.AntiAlias;

            // outter border
            if (width > 0)
            {
                using (Pen p = new Pen(XTheme.FormBorderOutterColor))
                {
                    using (GraphicsPath path = GraphicsPathHelper.CreateRoundedRect(
                        rect, Radius, Round, true))
                    {
                        g.DrawPath(p, path);
                    }
                }
            }
            width--;

            // inner border
            if (width > 0)
            {
                using (Pen p = new Pen(XTheme.FormBorderInnerColor))
                {
                    rect.Inflate(-1, -1);
                    using (GraphicsPath path = GraphicsPathHelper.CreateRoundedRect(
                        rect, Radius, Round, true))
                    {
                        g.DrawPath(p, path);
                    }
                }
            }
            width--;

            g.SmoothingMode = oldMode;

            // other inside border
            using (Pen p = new Pen(XTheme.FormBorderInmostColor))
            {
                while (width > 0)
                {
                    rect.Inflate(-1, -1);
                    g.DrawRectangle(p, rect);
                    width--;
                }
            }
        }

        /// <summary>
        /// to make the client area to  have 3D view
        /// </summary>        
        private void DrawInsetClientRect(Graphics g)
        {
            //if (this.DesignMode) { return; }
            int x = BorderWidth;
            int y = BorderWidth + CaptionHeight;
            int w = ClientSize.Width - BorderWidth * 2;
            int h = ClientSize.Height - BorderWidth * 2 - CaptionHeight;
            Rectangle clientRect = new Rectangle(x, y, w, h);
            clientRect.Width--;
            clientRect.Height--;

            Color inner = ColorHelper.GetDarkerColor(this.BackColor, 20);
            clientRect.Inflate(1, 1);
            using (Pen p1 = new Pen(inner))
            {
                g.DrawRectangle(p1, clientRect);
            }

            Color outter = Color.FromArgb(80, 255, 255, 255);
            clientRect.Inflate(1, 1);
            using (Pen p2 = new Pen(outter))
            {
                g.DrawRectangle(p2, clientRect);
            }
        }

        #endregion

        #region your Win-Message handler method

        private bool WmNcActivate(ref Message m)
        {
            // something here
            m.Result = Win32.WinAPI.TRUE;
            return true;
        }

        private bool WmNcCalcSize(ref Message m)
        {
            if (m.WParam == new IntPtr(1))
            {
                Win32.WinAPI.NCCALCSIZE_PARAMS info = (Win32.WinAPI.NCCALCSIZE_PARAMS)
                    Marshal.PtrToStructure(m.LParam, typeof(Win32.WinAPI.NCCALCSIZE_PARAMS));
                if (IsAboutToMaximize(info.rectNewForm))
                {
                    Rectangle workingRect = Screen.GetWorkingArea(this);
                    info.rectNewForm.Left = workingRect.Left - BorderWidth;
                    info.rectNewForm.Top = workingRect.Top - BorderWidth;
                    info.rectNewForm.Right = workingRect.Right + BorderWidth;
                    info.rectNewForm.Bottom = workingRect.Bottom + BorderWidth;
                    Marshal.StructureToPtr(info, m.LParam, false);
                }
            }
            return true;
        }

        private bool WmNcHitTest(ref Message m)
        {
            //int para = m.LParam.ToInt32();
            //var point = MousePosition;
            //int x0 = Win32.WinAPI.LOWORD(para);
            //int y0 = Win32.WinAPI.HIWORD(para);
            Point p = PointToClient(MousePosition);

            if (Resizable)
            {
                if (TopLeftRect.Contains(p))
                {
                    m.Result = new IntPtr((int)Win32.WinAPI.NCHITTEST.HTTOPLEFT);
                    return true;
                }

                if (TopRect.Contains(p))
                {
                    m.Result = new IntPtr((int)Win32.WinAPI.NCHITTEST.HTTOP);
                    return true;
                }

                if (TopRightRect.Contains(p))
                {
                    m.Result = new IntPtr((int)Win32.WinAPI.NCHITTEST.HTTOPRIGHT);
                    return true;
                }

                if (LeftRect.Contains(p))
                {
                    m.Result = new IntPtr((int)Win32.WinAPI.NCHITTEST.HTLEFT);
                    return true;
                }

                if (RightRect.Contains(p))
                {
                    m.Result = new IntPtr((int)Win32.WinAPI.NCHITTEST.HTRIGHT);
                    return true;
                }

                if (BottomLeftRect.Contains(p))
                {
                    m.Result = new IntPtr((int)Win32.WinAPI.NCHITTEST.HTBOTTOMLEFT);
                    return true;
                }

                if (BottomRect.Contains(p))
                {
                    m.Result = new IntPtr((int)Win32.WinAPI.NCHITTEST.HTBOTTOM);
                    return true;
                }

                if (BottomRightRect.Contains(p))
                {
                    m.Result = new IntPtr((int)Win32.WinAPI.NCHITTEST.HTBOTTOMRIGHT);
                    return true;
                }
            }

            if (IconRect.Contains(p))
            {
                m.Result = new IntPtr((int)Win32.WinAPI.NCHITTEST.HTSYSMENU);
                return true;
            }

            if (CloseBoxRect.Contains(p) || MaxBoxRect.Contains(p) || MinBoxRect.Contains(p))
            {
                m.Result = new IntPtr((int)Win32.WinAPI.NCHITTEST.HTCLIENT);
                return true;
            }

            if (IsMdiContainer && _mdiBarController != null)
            {
                if (_mdiBarController.HitTestBounds.Contains(p))
                {
                    m.Result = new IntPtr((int)Win32.WinAPI.NCHITTEST.HTCLIENT);
                    return true;
                }
            }

            if (CaptionRect.Contains(p))
            {
                m.Result = new IntPtr((int)Win32.WinAPI.NCHITTEST.HTCAPTION);
                return true;
            }

            m.Result = new IntPtr((int)Win32.WinAPI.NCHITTEST.HTCLIENT);
            return true;
        }

        #endregion

        #region override method
        /// <summary>
        /// 消息
        /// </summary>
        /// <param name="m"></param>
        protected override void WndProc(ref Message m)
        {
            //if (this.DesignMode) { base.WndProc(ref m); return; }
            bool alreadyHandled = false;
            switch (m.Msg)
            {
                case (int)Win32.WinAPI.WindowMessages.WM_NCCALCSIZE:
                    alreadyHandled = WmNcCalcSize(ref m);
                    break;
                case (int)Win32.WinAPI.WindowMessages.WM_NCHITTEST:
                    alreadyHandled = WmNcHitTest(ref m);
                    break;

                case (int)Win32.WinAPI.WindowMessages.WM_NCACTIVATE:
                    alreadyHandled = WmNcActivate(ref m);
                    break;

                case (int)Win32.WinAPI.WindowMessages.WM_NCPAINT:
                    alreadyHandled = true;
                    break;

                default:
                    break;
            }

            if (!alreadyHandled)
                base.WndProc(ref m);
        }
        /// <summary>
        /// 画UI
        /// </summary>
        /// <param name="e"></param>
        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);
            DrawFormBackground(e.Graphics);
            DrawCaptionBackground(e.Graphics);

            DrawFormBorder(e.Graphics);
            DrawFormIconAndText(e.Graphics);

            if (XTheme.SetClientInset)
                DrawInsetClientRect(e.Graphics);

            if (ControlBox)
                controlBoxManager.DrawBoxes(e.Graphics);

            if (IsMdiContainer && _mdiBarController != null)
                _mdiBarController.RenderTheBar(e.Graphics);
        }
        /// <summary>
        /// 在画背景时激发
        /// </summary>
        /// <param name="e"></param>
        protected override void OnPaintBackground(PaintEventArgs e)
        {
            //base.OnPaintBackground(e);
        }
        ///// <summary>
        ///// 重写该方法解决窗体每次还原都会变大的问题
        ///// </summary>        
        //protected override void SetBoundsCore(int x, int y, int width, int height, BoundsSpecified specified)
        //{
        //    if (base.WindowState == FormWindowState.Normal)
        //    {
        //        if (this.Size == this.ClientSize)
        //        {
        //            //if (width == (this.Size.Width + SystemInformation.FrameBorderSize.Width * 2))
        //            if (width == (this.Size.Width + 16))
        //            {
        //                width = this.Size.Width;
        //                height = this.Size.Height;

        //            }
        //        }
        //    }
        //    base.SetBoundsCore(x, y, width, height, specified);
        //}

        /// <summary>
        /// 重写该方法解决在VS设计器中，每次保存一个新的尺寸，再打开尺寸会变大的问题
        /// </summary>        
        protected override void SetClientSizeCore(int x, int y)
        {
            //MessageBox.Show("before SetClientSizeCore,size:" +
            //    base.Size.ToString() + ", clisize:" + base.ClientSize.ToString()
            //    + ", x:" + x.ToString() + ", y:" + y.ToString());

            if (base.WindowState == FormWindowState.Normal && DesignMode)
            {
                if (base.Size != base.ClientSize)
                {
                    int diffx = Size.Width - ClientSize.Width;
                    int diffy = Size.Height - ClientSize.Height;
                    //MessageBox.Show(diffx+"-"+ diffy);
                    if (diffx == 16)
                    {
                        x -= diffx;
                        y -= diffy;
                    }
                }
            }
            base.SetClientSizeCore(x, y);

            //MessageBox.Show(base.SizeFromClientSize(new Size(x,y)).ToString());

            //MessageBox.Show("after SetClientSizeCore,size:" +
            //    base.Size.ToString() + ", clisize:" + base.ClientSize.ToString()
            //    + ", x:" + x.ToString() + ", y:" + y.ToString());

        }
        /// <summary>
        /// 创建控件时激发
        /// </summary>
        protected override void OnCreateControl()
        {
            base.OnCreateControl();
            SetFormRegion();
        }
        /// <summary>
        /// 窗体可见变化时激发
        /// </summary>
        /// <param name="e"></param>
        protected override void OnVisibleChanged(EventArgs e)
        {
            base.OnVisibleChanged(e);
            if (_shawdowForm != null)
                _shawdowForm.Visible = base.Visible;
        }

        /// <summary>
        /// 大小改变时激发
        /// </summary>
        /// <param name="e"></param>
        protected override void OnSizeChanged(EventArgs e)
        {
            base.OnSizeChanged(e);
            SetFormRegion();

            if (ControlBox && controlBoxManager!=null)
                controlBoxManager.FormResize();

            if (XTheme.ShowShadow && _shawdowForm != null
                && !_shawdowForm.IsDisposed)
            {
                if (base.WindowState == FormWindowState.Normal)
                {
                    _shawdowForm.Visible = true;
                    SetShadowFormSize();
                }
                else
                {
                    _shawdowForm.Visible = false;
                }
            }

        }
        /// <summary>
        /// 在位置变化时激发
        /// </summary>
        /// <param name="e"></param>
        protected override void OnLocationChanged(EventArgs e)
        {
            base.OnLocationChanged(e);

            if (XTheme.ShowShadow && _shawdowForm != null
                && !_shawdowForm.IsDisposed && _shawdowForm.Visible)
                SetShadowFormLocation();
        }
        /// <summary>
        /// 窗体激活
        /// </summary>
        /// <param name="e"></param>
        protected override void OnActivated(EventArgs e)
        {
            base.OnActivated(e);
            if (XTheme.ShowShadow && !base.IsMdiChild)
            {
                if (_shawdowForm == null)
                {
                    _shawdowForm = new GMShadow(this);
                    SetShadowFormSize();
                    SetShadowFormLocation();
                    _shawdowForm.Show(this);
                    SetShadowFormSize();
                    SetShadowFormLocation();

                    _shawdowForm.TopMost = base.TopMost;

                    var size = base.MinimumSize;
                    size.Width += ShadowWidth * 2;
                    size.Height += ShadowWidth * 2;
                    _shawdowForm.MinimumSize = size;

                    if (XTheme.UseShadowToResize)
                        _shawdowForm.BeginToResizeOwner();
                }
            }
        }
        /// <summary>
        /// 窗体关闭后激发
        /// </summary>
        /// <param name="e"></param>
        protected override void OnFormClosed(FormClosedEventArgs e)
        {
            if (_shawdowForm != null && !_shawdowForm.IsDisposed)
                _shawdowForm.Close();

            base.OnFormClosed(e);
        }
        /// <summary>
        /// 加载时
        /// </summary>
        /// <param name="e"></param>
        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);

            if (base.IsMdiContainer)
            {
                SetMdiClient();
                _listClosedMdiChild = new List<Form>();
                _mdiBarController = new MdiBarController(this);
                _mdiBarController.TabCloseButtonClick += new EventHandler(OnMdiTabCloseButtonClick);
                _mdiBarController.NewTabButtonClick += new EventHandler(OnMdiNewTabButtonClick);
                OnMdiBarCreated(this, EventArgs.Empty);
            }
        }
        /// <summary>
        /// 在子窗体激活时激发
        /// </summary>
        /// <param name="e"></param>
        protected override void OnMdiChildActivate(EventArgs e)
        {
            base.OnMdiChildActivate(e);
            Invalidate();
        }
        /// <summary>
        /// 标签菜单
        /// </summary>
        public ContextMenuStrip TabContextMenuStrip { get; set; } = null;
        /// <summary>
        /// 窗体上移动鼠标时激发
        /// </summary>
        /// <param name="e"></param>
        protected override void OnMouseMove(MouseEventArgs e)
        {
            base.OnMouseMove(e);
            if (ControlBox)
                controlBoxManager.MouseOperation(e.Location, MouseOperationType.Move);
            if (IsMdiContainer && _mdiBarController != null)
                _mdiBarController.MouseOperation(e.Location, MouseOperationType.Move);
        }
        /// <summary>
        /// 获取当前点击的标签项
        /// </summary>
        public Form ClickTab { get; set; } = null;
        /// <summary>
        /// 在窗体上按下鼠标时激发
        /// </summary>
        /// <param name="e"></param>
        protected override void OnMouseDown(MouseEventArgs e)
        {
            base.OnMouseDown(e);

            if (e.Button != System.Windows.Forms.MouseButtons.Left)
            {
                return;
            }

            if (ControlBox)
                controlBoxManager.MouseOperation(e.Location, MouseOperationType.Down);
            if (IsMdiContainer && _mdiBarController != null)
                _mdiBarController.MouseOperation(e.Location, MouseOperationType.Down);
        }
        /// <summary>
        /// 在窗体上放开鼠标时激发
        /// </summary>
        /// <param name="e"></param>
        protected override void OnMouseUp(MouseEventArgs e)
        {
            base.OnMouseUp(e);

            if (e.Button != System.Windows.Forms.MouseButtons.Left)
            {
                if (e.Button == System.Windows.Forms.MouseButtons.Right)
                {
                    if (TabContextMenuStrip != null)
                    {
                        foreach (MdiGMTabItem tab in _mdiBarController._listTabItems)
                        {
                            if (!tab.IsHidden)
                            {
                                if (tab.Bounds.Contains(e.Location) && !tab.CloseBtnRect.Contains(e.Location))
                                {
                                    ClickTab = tab.Form;
                                    TabContextMenuStrip.Show(PointToScreen(e.Location));
                                    break;
                                }
                            }
                        }

                    }
                }
                return;
            }

            if (e.Clicks > 1)
                return;

            if (ControlBox)
                controlBoxManager.MouseOperation(e.Location, MouseOperationType.Up);
            if (IsMdiContainer && _mdiBarController != null)
                _mdiBarController.MouseOperation(e.Location, MouseOperationType.Up);
        }
        /// <summary>
        /// 在鼠标离开窗体时激发
        /// </summary>
        /// <param name="e"></param>
        protected override void OnMouseLeave(EventArgs e)
        {
            base.OnMouseLeave(e);
            if (ControlBox)
                controlBoxManager.MouseOperation(Point.Empty, MouseOperationType.Leave);
            if (IsMdiContainer && _mdiBarController != null)
                _mdiBarController.MouseOperation(Point.Empty, MouseOperationType.Leave);
        }

        #endregion

        private void GMForm_Load(object sender, EventArgs e)
        {
            //var size = this.ClientSize;
        }
    }
}
