/******************************************************************************
 * SunnyUI 开源控件库、工具类库、扩展类库、多页面开发框架。
 * CopyRight (C) 2012-2024 ShenYongHua(沈永华).
 * QQ群：56829229 QQ：17612584 EMail：SunnyUI@QQ.Com
 *
 * Blog:   https://www.cnblogs.com/yhuse
 * Gitee:  https://gitee.com/yhuse/SunnyUI
 * GitHub: https://github.com/yhuse/SunnyUI
 *
 * SunnyUI.dll can be used for free under the GPL-3.0 license.
 * If you use this code, please keep this note.
 * 如果您使用此代码，请保留此说明。
 ******************************************************************************
 * 文件名称: UIForm2.cs
 * 文件说明: 窗体基类
 * 当前版本: V3.6
 * 创建日期: 2024-01-20
 *
 * 2024-01-20: V3.6.3 增加文件说明
 * 2024-01-25: V3.6.3 增加主题等
 * 2024-04-16: V3.6.5 设置默认Padding.Top为TitleHeight
 * 2024-04-28: V3.6.5 增加WindowStateChanged事件
 * 2024-05-16: V3.6.6 Resizable替代ShowDragStretch，显示边框可拖拽调整窗体大小
 * 2024-06-08: V3.6.6 防止图标转换错误
 * 2024-07-20: V3.6.8 修改最大化时按钮位置
 * 2024-07-21: V3.6.8 修改属性与UIForm兼容
 * 2024-07-26: V3.6.8 修复鼠标点击事件
******************************************************************************/

using System;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Drawing;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace Sunny.UI
{
    public partial class UIForm2 : UIBaseForm
    {
        public UIForm2()
        {
            InitializeComponent();

            SetStyle(ControlStyles.UserPaint | ControlStyles.DoubleBuffer | ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint, true);
            UpdateStyles();

            fieldW = typeof(Control).GetField("_clientWidth", BindingFlags.NonPublic | BindingFlags.Instance) ?? typeof(Control).GetField("clientWidth", BindingFlags.NonPublic | BindingFlags.Instance);
            fieldH = typeof(Control).GetField("_clientHeight", BindingFlags.NonPublic | BindingFlags.Instance) ?? typeof(Control).GetField("clientHeight", BindingFlags.NonPublic | BindingFlags.Instance);
        }

        /// <summary>
        /// 禁止控件跟随窗体缩放
        /// </summary>
        [DefaultValue(false), Category("SunnyUI"), Description("禁止控件跟随窗体缩放")]
        public bool ZoomScaleDisabled { get; set; }

        private void SetZoomScaleRect()
        {
            if (ZoomScaleRect.Width == 0 && ZoomScaleRect.Height == 0)
            {
                ZoomScaleRect = new Rectangle(ZoomScaleSize.Width, ZoomScaleSize.Height, 0, 0);
            }

            if (ZoomScaleRect.Width == 0 && ZoomScaleRect.Height == 0)
            {
                ZoomScaleRect = new Rectangle(Left, Top, Width, Height);
            }

            ZoomScaleRectChanged?.Invoke(this, ZoomScaleRect);
        }

        public event OnZoomScaleRectChanged ZoomScaleRectChanged;

        [DefaultValue(typeof(Size), "0, 0")]
        [Description("设计界面大小"), Category("SunnyUI")]
        public Size ZoomScaleSize
        {
            get;
            set;
        }

        /// <summary>
        /// 控件缩放前在其容器里的位置
        /// </summary>
        [Browsable(false), DefaultValue(typeof(Rectangle), "0, 0, 0, 0")]
        public Rectangle ZoomScaleRect { get; set; }

        /// <summary>
        /// 设置控件缩放比例
        /// </summary>
        /// <param name="scale">缩放比例</param>
        private void SetZoomScale()
        {
            if (ZoomScaleDisabled) return;
            if (!UIStyles.DPIScale || !UIStyles.ZoomScale) return;
            if (ZoomScaleRect.Width == 0 || ZoomScaleRect.Height == 0) return;
            if (Width == 0 || Height == 0) return;
            float scale = Math.Min(Width * 1.0f / ZoomScaleRect.Width, Height * 1.0f / ZoomScaleRect.Height);
            if (scale.EqualsFloat(0)) return;
            foreach (Control control in this.GetAllZoomScaleControls())
            {
                if (control is IZoomScale ctrl)
                {
                    UIZoomScale.SetZoomScale(control, scale);
                }
            }

            ZoomScaleChanged?.Invoke(this, scale);
        }

        public event OnZoomScaleChanged ZoomScaleChanged;

        protected override void OnShown(EventArgs e)
        {
            base.OnShown(e);
            SetZoomScaleRect();
        }

        [Description("显示边框可拖拽调整窗体大小"), Category("SunnyUI"), DefaultValue(false)]
        public bool Resizable
        {
            get => showDragStretch;
            set => showDragStretch = value;
        }

        [Browsable(false)]
        [Description("显示边框可拖拽调整窗体大小"), Category("SunnyUI"), DefaultValue(false)]
        public bool ShowDragStretch
        {
            get => showDragStretch;
            set
            {
                showDragStretch = value;
                SetPadding();
            }
        }

        /// <summary>
        /// 重载绘图
        /// </summary>
        /// <param name="e">绘图参数</param>
        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);

            if (Width <= 0 || Height <= 0)
            {
                return;
            }

            if (ShowTitle)
            {
                e.Graphics.FillRectangle(titleColor, 0, 0, Width, TitleHeight);
                e.Graphics.DrawLine(RectColor, 0, titleHeight, Width, titleHeight);
            }

            if (!ShowTitle)
            {
                return;
            }

            int titleLeft = 6;
            if (ShowIcon && Icon != null)
            {
                try
                {
                    if (IconImage != null)
                    {
                        e.Graphics.DrawImage(IconImage, new Rectangle(6, (TitleHeight - IconImageSize) / 2 + 1, IconImageSize, IconImageSize), new Rectangle(0, 0, IconImage.Width, IconImage.Height), GraphicsUnit.Pixel);
                        titleLeft = 6 + IconImageSize + 2;
                    }
                    else
                    {
                        using (Image image = IconToImage(Icon))
                        {
                            e.Graphics.DrawImage(image, 6, (TitleHeight - 24) / 2 + 1, 24, 24);
                        }

                        titleLeft = 6 + 24 + 2;
                    }
                }
                catch
                {
                    Console.WriteLine("图标转换错误");
                }
            }

            if (TextAlignment == StringAlignment.Center)
            {
                e.Graphics.DrawString(Text, TitleFont, titleForeColor, new Rectangle(0, 0, Width, TitleHeight), ContentAlignment.MiddleCenter);
            }
            else
            {
                e.Graphics.DrawString(Text, TitleFont, titleForeColor, new Rectangle(titleLeft, 0, Width, TitleHeight), ContentAlignment.MiddleLeft);
            }

            e.Graphics.SetHighQuality();

            if (ControlBoxLeft != Width)
            {
                e.Graphics.FillRectangle(TitleColor, new Rectangle(ControlBoxLeft, 1, Width, TitleHeight - 2));
            }

            if (ControlBox)
            {
                if (InControlBox)
                {
                    if (WindowState == FormWindowState.Maximized)
                    {
                        e.Graphics.FillRectangle(ControlBoxCloseFillHoverColor, new Rectangle(ControlBoxRect.Left, 0, Width - ControlBoxRect.Left, TitleHeight));
                    }
                    else
                    {
                        e.Graphics.FillRectangle(ControlBoxCloseFillHoverColor, ControlBoxRect);
                    }
                }

                e.Graphics.DrawLine(controlBoxForeColor,
                    ControlBoxRect.Left + ControlBoxRect.Width / 2 - 5,
                    ControlBoxRect.Top + ControlBoxRect.Height / 2 - 5,
                    ControlBoxRect.Left + ControlBoxRect.Width / 2 + 5,
                    ControlBoxRect.Top + ControlBoxRect.Height / 2 + 5);
                e.Graphics.DrawLine(controlBoxForeColor,
                    ControlBoxRect.Left + ControlBoxRect.Width / 2 - 5,
                    ControlBoxRect.Top + ControlBoxRect.Height / 2 + 5,
                    ControlBoxRect.Left + ControlBoxRect.Width / 2 + 5,
                    ControlBoxRect.Top + ControlBoxRect.Height / 2 - 5);
            }

            if (MaximizeBox)
            {
                if (InMaxBox)
                {
                    e.Graphics.FillRectangle(ControlBoxFillHoverColor, MaximizeBoxRect);
                }

                if (WindowState == FormWindowState.Maximized)
                {
                    e.Graphics.DrawRectangle(controlBoxForeColor,
                        MaximizeBoxRect.Left + MaximizeBoxRect.Width / 2 - 5,
                        MaximizeBoxRect.Top + MaximizeBoxRect.Height / 2 - 1,
                        7, 7);

                    e.Graphics.DrawLine(controlBoxForeColor,
                        MaximizeBoxRect.Left + MaximizeBoxRect.Width / 2 - 2,
                        MaximizeBoxRect.Top + MaximizeBoxRect.Height / 2 - 1,
                        MaximizeBoxRect.Left + MaximizeBoxRect.Width / 2 - 2,
                        MaximizeBoxRect.Top + MaximizeBoxRect.Height / 2 - 4);

                    e.Graphics.DrawLine(controlBoxForeColor,
                        MaximizeBoxRect.Left + MaximizeBoxRect.Width / 2 - 2,
                        MaximizeBoxRect.Top + MaximizeBoxRect.Height / 2 - 4,
                        MaximizeBoxRect.Left + MaximizeBoxRect.Width / 2 + 5,
                        MaximizeBoxRect.Top + MaximizeBoxRect.Height / 2 - 4);

                    e.Graphics.DrawLine(controlBoxForeColor,
                        MaximizeBoxRect.Left + MaximizeBoxRect.Width / 2 + 5,
                        MaximizeBoxRect.Top + MaximizeBoxRect.Height / 2 - 4,
                        MaximizeBoxRect.Left + MaximizeBoxRect.Width / 2 + 5,
                        MaximizeBoxRect.Top + MaximizeBoxRect.Height / 2 + 3);

                    e.Graphics.DrawLine(controlBoxForeColor,
                        MaximizeBoxRect.Left + MaximizeBoxRect.Width / 2 + 5,
                        MaximizeBoxRect.Top + MaximizeBoxRect.Height / 2 + 3,
                        MaximizeBoxRect.Left + MaximizeBoxRect.Width / 2 + 3,
                        MaximizeBoxRect.Top + MaximizeBoxRect.Height / 2 + 3);
                }

                if (WindowState == FormWindowState.Normal)
                {
                    e.Graphics.DrawRectangle(controlBoxForeColor,
                        MaximizeBoxRect.Left + MaximizeBoxRect.Width / 2 - 5,
                        MaximizeBoxRect.Top + MaximizeBoxRect.Height / 2 - 4,
                        10, 9);
                }
            }

            if (MinimizeBox)
            {
                if (InMinBox)
                {
                    e.Graphics.FillRectangle(ControlBoxFillHoverColor, MinimizeBoxRect);
                }

                e.Graphics.DrawLine(controlBoxForeColor,
                    MinimizeBoxRect.Left + MinimizeBoxRect.Width / 2 - 6,
                    MinimizeBoxRect.Top + MinimizeBoxRect.Height / 2,
                    MinimizeBoxRect.Left + MinimizeBoxRect.Width / 2 + 5,
                    MinimizeBoxRect.Top + MinimizeBoxRect.Height / 2);
            }

            if (ExtendBox)
            {
                if (InExtendBox)
                {
                    e.Graphics.FillRectangle(ControlBoxFillHoverColor, ExtendBoxRect);
                }

                if (ExtendSymbol == 0)
                {
                    e.Graphics.DrawLine(controlBoxForeColor,
                        ExtendBoxRect.Left + ExtendBoxRect.Width / 2 - 5 - 1,
                        ExtendBoxRect.Top + ExtendBoxRect.Height / 2 - 2,
                        ExtendBoxRect.Left + ExtendBoxRect.Width / 2 - 1,
                        ExtendBoxRect.Top + ExtendBoxRect.Height / 2 + 3);

                    e.Graphics.DrawLine(controlBoxForeColor,
                        ExtendBoxRect.Left + ExtendBoxRect.Width / 2 + 5 - 1,
                        ExtendBoxRect.Top + ExtendBoxRect.Height / 2 - 2,
                        ExtendBoxRect.Left + ExtendBoxRect.Width / 2 - 1,
                        ExtendBoxRect.Top + ExtendBoxRect.Height / 2 + 3);
                }
                else
                {
                    e.Graphics.DrawFontImage(ExtendSymbol, ExtendSymbolSize, controlBoxForeColor, ExtendBoxRect, ExtendSymbolOffset.X, ExtendSymbolOffset.Y);
                }
            }

            e.Graphics.SetDefaultQuality();
        }

        protected override void OnMouseDoubleClick(MouseEventArgs e)
        {
            if (InControlBox || InMaxBox || InMinBox || InExtendBox) return;
            if (!ShowTitle || e.Y > Padding.Top)
                base.OnMouseDoubleClick(e);
        }

        protected override void OnMouseClick(MouseEventArgs e)
        {
            if (ShowTitle)
            {
                if (InControlBox)
                {
                    InControlBox = false;
                    Close();
                }

                if (InMinBox)
                {
                    InMinBox = false;
                    DoWindowStateChanged(FormWindowState.Minimized);
                    WindowState = FormWindowState.Minimized;
                }

                if (InMaxBox)
                {
                    InMaxBox = false;
                    ShowMaxOrNormal();
                }

                if (InExtendBox)
                {
                    InExtendBox = false;
                    if (ExtendMenu != null)
                    {
                        this.ShowContextMenuStrip(ExtendMenu, ExtendBoxRect.Left, TitleHeight - 1);
                    }
                    else
                    {
                        ExtendBoxClick?.Invoke(this, EventArgs.Empty);
                    }
                }
            }

            base.OnMouseClick(e);
        }

        /// <summary>
        /// 重载鼠标移动事件
        /// </summary>
        /// <param name="e">鼠标参数</param>
        protected override void OnMouseMove(MouseEventArgs e)
        {
            bool inControlBox = e.Location.InRect(ControlBoxRect);
            if (WindowState == FormWindowState.Maximized && ControlBox)
            {
                if (e.Location.X > ControlBoxRect.Left && e.Location.Y < TitleHeight)
                    inControlBox = true;
            }

            bool inMaxBox = e.Location.InRect(MaximizeBoxRect);
            bool inMinBox = e.Location.InRect(MinimizeBoxRect);
            bool inExtendBox = e.Location.InRect(ExtendBoxRect);
            bool isChange = false;

            if (inControlBox != InControlBox)
            {
                InControlBox = inControlBox;
                isChange = true;
            }

            if (inMaxBox != InMaxBox)
            {
                InMaxBox = inMaxBox;
                isChange = true;
            }

            if (inMinBox != InMinBox)
            {
                InMinBox = inMinBox;
                isChange = true;
            }

            if (inExtendBox != InExtendBox)
            {
                InExtendBox = inExtendBox;
                isChange = true;
            }

            if (isChange)
            {
                Invalidate();
            }

            base.OnMouseMove(e);
        }

        public event EventHandler ExtendBoxClick;

        private void ShowMaxOrNormal()
        {
            if (!ShowFullScreen)
            {
                if (WindowState == FormWindowState.Maximized)
                {
                    DoWindowStateChanged(FormWindowState.Normal);
                    WindowState = FormWindowState.Normal;
                    if (Location.Y < 0) Location = new Point(Location.X, 0);
                }
                else
                {
                    DoWindowStateChanged(FormWindowState.Maximized);
                    WindowState = FormWindowState.Maximized;
                }
            }
            else
            {
                if (WindowState == FormWindowState.Maximized)
                {
                    FormBorderStyle = FormBorderStyle.Sizable;
                    DoWindowStateChanged(FormWindowState.Normal);
                    WindowState = FormWindowState.Normal;
                    if (Location.Y < 0) Location = new Point(Location.X, 0);
                }
                else
                {
                    FormBorderStyle = FormBorderStyle.None;
                    DoWindowStateChanged(FormWindowState.Maximized);
                    WindowState = FormWindowState.Maximized;
                }
            }
        }

        /// <summary>
        /// 重载鼠标按下事件
        /// </summary>
        /// <param name="e">鼠标参数</param>
        protected override void OnMouseDown(MouseEventArgs e)
        {
            base.OnMouseDown(e);

            if (InControlBox || InMaxBox || InMinBox || InExtendBox) return;
            if (!ShowTitle) return;
            if (e.Y > Padding.Top) return;
            if (e.X > ControlBoxLeft) return;
            if (!Movable) return;

            if (e.Clicks == 1)
            {
                Win32.User.ReleaseCapture();
                Win32.User.SendMessage(this.Handle, Win32.User.WM_SYSCOMMAND, Win32.User.SC_MOVE + Win32.User.HTCAPTION, 0);
            }
            else
            {
                if (FormBorderStyle == FormBorderStyle.Sizable)
                    ShowMaxOrNormal();
            }
        }

        /// <summary>
        /// 重载控件尺寸变更
        /// </summary>
        /// <param name="e">参数</param>
        protected override void OnSizeChanged(EventArgs e)
        {
            base.OnSizeChanged(e);
            CalcSystemBoxPos();
            Invalidate();
        }

        protected override void CalcSystemBoxPos()
        {
            ControlBoxLeft = Width;

            if (ControlBox)
            {
                ControlBoxRect = new Rectangle(Width - 6 - 28, titleHeight / 2 - 14, 28, 28);
                ControlBoxLeft = ControlBoxRect.Left - 2;

                if (MaximizeBox)
                {
                    MaximizeBoxRect = new Rectangle(ControlBoxRect.Left - 28 - 2, ControlBoxRect.Top, 28, 28);
                    ControlBoxLeft = MaximizeBoxRect.Left - 2;
                }
                else
                {
                    MaximizeBoxRect = new Rectangle(Width + 1, Height + 1, 1, 1);
                }

                if (MinimizeBox)
                {
                    MinimizeBoxRect = new Rectangle(MaximizeBox ? MaximizeBoxRect.Left - 28 - 2 : ControlBoxRect.Left - 28 - 2, ControlBoxRect.Top, 28, 28);
                    ControlBoxLeft = MinimizeBoxRect.Left - 2;
                }
                else
                {
                    MinimizeBoxRect = new Rectangle(Width + 1, Height + 1, 1, 1);
                }

                if (ExtendBox)
                {
                    if (MinimizeBox)
                    {
                        ExtendBoxRect = new Rectangle(MinimizeBoxRect.Left - 28 - 2, ControlBoxRect.Top, 28, 28);
                    }
                    else
                    {
                        ExtendBoxRect = new Rectangle(ControlBoxRect.Left - 28 - 2, ControlBoxRect.Top, 28, 28);
                    }

                    ControlBoxLeft = ExtendBoxRect.Left - 2;
                }

                if (ControlBoxLeft != Width) ControlBoxLeft -= 6;
            }
            else
            {
                ExtendBoxRect = MaximizeBoxRect = MinimizeBoxRect = ControlBoxRect = new Rectangle(Width + 1, Height + 1, 1, 1);
            }
        }

        private FormWindowState winState = FormWindowState.Normal;

        protected override void WndProc(ref System.Windows.Forms.Message m)
        {
            var msg = (int)m.Msg;
            switch (msg)
            {
                case Win32.User.WM_ACTIVATE:
                    var margins = new Win32.Dwm.MARGINS(0, 0, 1, 0);
                    Win32.Dwm.DwmExtendFrameIntoClientArea(Handle, ref margins);
                    if (WindowState != FormWindowState.Minimized && lastWindowState == FormWindowState.Minimized)
                    {
                        DoWindowStateChanged(WindowState, lastWindowState);
                        lastWindowState = WindowState;
                    }
                    break;
                case Win32.User.WM_NCCALCSIZE when m.WParam != IntPtr.Zero:
                    if (WM_NCCALCSIZE(ref m)) return;
                    break;
                case Win32.User.WM_NCACTIVATE:
                    if (WM_NCACTIVATE(ref m)) return;
                    break;
                case Win32.User.WM_SIZE:
                    WM_SIZE(ref m);
                    break;
                case Win32.User.WM_HOTKEY:
                    int hotKeyId = (int)(m.WParam);
                    if (hotKeys != null && hotKeys.ContainsKey(hotKeyId))
                    {
                        HotKeyEventHandler?.Invoke(this, new HotKeyEventArgs(hotKeys[hotKeyId], DateTime.Now));
                    }
                    break;
                case Win32.User.WM_ACTIVATEAPP:
                    if (WindowState == FormWindowState.Minimized && lastWindowState != FormWindowState.Minimized)
                    {
                        DoWindowStateChanged(WindowState, lastWindowState);
                        lastWindowState = FormWindowState.Minimized;
                    }
                    break;
            }

            base.WndProc(ref m);

            if (m.Msg == Win32.User.WM_NCHITTEST && ShowDragStretch && WindowState == FormWindowState.Normal)
            {
                //Point vPoint = new Point((int)m.LParam & 0xFFFF, (int)m.LParam >> 16 & 0xFFFF);
                Point vPoint = new Point(MousePosition.X, MousePosition.Y);//修正有分屏后，调整窗体大小时鼠标显示左右箭头问题
                vPoint = PointToClient(vPoint);
                int dragSize = 5;
                if (vPoint.X <= dragSize)
                {
                    if (vPoint.Y <= dragSize)
                        m.Result = (IntPtr)Win32.User.HTTOPLEFT;
                    else if (vPoint.Y >= ClientSize.Height - dragSize)
                        m.Result = (IntPtr)Win32.User.HTBOTTOMLEFT;
                    else
                        m.Result = (IntPtr)Win32.User.HTLEFT;
                }
                else if (vPoint.X >= ClientSize.Width - dragSize)
                {
                    if (vPoint.Y <= dragSize)
                        m.Result = (IntPtr)Win32.User.HTTOPRIGHT;
                    else if (vPoint.Y >= ClientSize.Height - dragSize)
                        m.Result = (IntPtr)Win32.User.HTBOTTOMRIGHT;
                    else
                        m.Result = (IntPtr)Win32.User.HTRIGHT;
                }
                else if (vPoint.Y <= dragSize)
                {
                    m.Result = (IntPtr)Win32.User.HTTOP;
                }
                else if (vPoint.Y >= ClientSize.Height - dragSize)
                {
                    m.Result = (IntPtr)Win32.User.HTBOTTOM;
                }
            }
        }

        public event HotKeyEventHandler HotKeyEventHandler;

        public new Point Location
        {
            get => winState == FormWindowState.Normal ? base.Location : FormRect.Location;
            set => base.Location = value;
        }

        public new int Top
        {
            get => Location.Y;
            set => base.Top = value;
        }

        public new int Left
        {
            get => Location.X;
            set => base.Left = value;
        }

        public new int Right => FormRect.Right;

        public new int Bottom => FormRect.Bottom;

        public new Size Size
        {
            get => winState == FormWindowState.Normal ? base.Size : FormRect.Size;
            set => base.Size = value;
        }

        public new int Width
        {
            get => Size.Width;
            set => base.Width = value;
        }

        public new int Height
        {
            get => Size.Height;
            set => base.Height = value;
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Always)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        private Rectangle FormRect
        {
            get
            {
                if (winState == FormWindowState.Normal) return new Rectangle(base.Location, base.Size);
                var rect = ClientRectangle;
                var point = RectangleToScreen(Rectangle.Empty);
                return new Rectangle(point.Location, rect.Size);
            }
            set
            {
                base.Location = value.Location;
                base.Size = value.Size;
            }
        }

        private void WM_SIZE(ref System.Windows.Forms.Message m)
        {
            if ((int)m.WParam == Win32.User.SIZE_MINIMIZED)
            {
                winState = FormWindowState.Minimized;
            }
            else if ((int)m.WParam == Win32.User.SIZE_MAXIMIZED)
            {
                winState = FormWindowState.Maximized;
                boundsCoreState = true;
                CalcSystemBoxPos();
                Invalidate();
            }
            else if ((int)m.WParam == Win32.User.SIZE_RESTORED)
            {
                winState = FormWindowState.Normal;
            }
        }

        private bool WM_NCCALCSIZE(ref System.Windows.Forms.Message m)
        {
            if (FormBorderStyle == FormBorderStyle.None) return false;
#if NET40
            var sizeParams = (Win32.NCCALCSIZE_PARAMS)Marshal.PtrToStructure(m.LParam, typeof(Win32.NCCALCSIZE_PARAMS));
#else
            var sizeParams = Marshal.PtrToStructure<Win32.NCCALCSIZE_PARAMS>(m.LParam);
#endif
            var borders = GetBorders();

            if (Win32.User.IsZoomed(Handle) == 1)
            {
                sizeParams.rgrc0.Top -= borders.Top;
                sizeParams.rgrc0.Top += borders.Bottom;
                Marshal.StructureToPtr(sizeParams, m.LParam, false);
            }
            else
            {
                m.Result = new IntPtr(1);
                return true;
            }

            m.Result = new IntPtr(0x0400);
            return false;
        }

        private bool WM_NCACTIVATE(ref System.Windows.Forms.Message m)
        {
            if (m.HWnd == IntPtr.Zero) return false;
            if (IsIconic(m.HWnd)) return false;
            m.Result = DefWindowProc(m.HWnd, (uint)m.Msg, m.WParam, new IntPtr(-1));
            return true;
        }

        [DllImport("user32.dll", SetLastError = false, CharSet = CharSet.Auto)]
        internal static extern IntPtr DefWindowProc(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);

        [DllImport("user32.dll", SetLastError = false, ExactSpelling = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        internal static extern bool IsIconic(IntPtr hWnd);

        private FieldInfo fieldW;
        private FieldInfo fieldH;
        protected override void SetClientSizeCore(int x, int y)
        {
            if (DesignMode && fieldW != null && fieldH != null)
            {
                fieldW.SetValue(this, x);
                fieldH.SetValue(this, y);
                OnClientSizeChanged(EventArgs.Empty);
                Size = SizeFromClientSize(new Size(x, y));
            }
            else base.SetClientSizeCore(x, y);
        }

        private Padding GetBorders()
        {
            var screenRect = ClientRectangle;
            screenRect.Offset(-Bounds.Left, -Bounds.Top);
            var rect = new Win32.RECT(screenRect.Left, screenRect.Top, screenRect.Right, screenRect.Bottom);
            Win32.User.AdjustWindowRectEx(ref rect, (int)CreateParams.Style, false, (int)CreateParams.ExStyle);
            return new Padding
            {
                Top = screenRect.Top - rect.Top,
                Left = screenRect.Left - rect.Left,
                Bottom = rect.Bottom - screenRect.Bottom,
                Right = rect.Right - screenRect.Right
            };
        }

        protected override void SetBoundsCore(int x, int y, int width, int height, BoundsSpecified specified)
        {
            if (boundsCoreState && base.WindowState != FormWindowState.Minimized)
            {
                if (y != Top) y = Top;
                if (x != Left) x = Left;
                boundsCoreState = false;
            }
            var size = SetBoundsCore(width, height);
            base.SetBoundsCore(x, y, size.Width, size.Height, specified);
        }

        protected override Rectangle GetScaledBounds(Rectangle bounds, SizeF factor, BoundsSpecified specified)
        {
            var rect = base.GetScaledBounds(bounds, factor, specified);
            if (!GetStyle(ControlStyles.FixedWidth) && (specified & BoundsSpecified.Width) != BoundsSpecified.None)
            {
                var clientWidth = bounds.Width;// - sz.Width;
                rect.Width = (int)Math.Round((double)(clientWidth * factor.Width));// + sz.Width;
            }
            if (!GetStyle(ControlStyles.FixedHeight) && (specified & BoundsSpecified.Height) != BoundsSpecified.None)
            {
                var clientHeight = bounds.Height;// - sz.Height;
                rect.Height = (int)Math.Round((double)(clientHeight * factor.Height));// + sz.Height;
            }
            return rect;
        }

        protected override Size SizeFromClientSize(Size clientSize)
        {
            return clientSize;
        }

        private bool boundsCoreState = false;

        private Size SetBoundsCore(int width, int height)
        {
            if (WindowState == FormWindowState.Normal)
            {
                var boundsSpecified = typeof(Form).GetField("restoredWindowBoundsSpecified", BindingFlags.NonPublic | BindingFlags.Instance) ?? typeof(Form).GetField("_restoredWindowBoundsSpecified", BindingFlags.NonPublic | BindingFlags.Instance);
                var restoredSpecified = (BoundsSpecified)boundsSpecified!.GetValue(this)!;

                if ((restoredSpecified & BoundsSpecified.Size) != BoundsSpecified.None)
                {
                    var boundsField = typeof(Form).GetField("FormStateExWindowBoundsWidthIsClientSize", BindingFlags.NonPublic | BindingFlags.Static);
                    var stateField = typeof(Form).GetField("formStateEx", BindingFlags.NonPublic | BindingFlags.Instance) ?? typeof(Form).GetField("_formStateEx", BindingFlags.NonPublic | BindingFlags.Instance);
                    var restoredField = typeof(Form).GetField("restoredWindowBounds", BindingFlags.NonPublic | BindingFlags.Instance) ?? typeof(Form).GetField("_restoredWindowBounds", BindingFlags.NonPublic | BindingFlags.Instance);

                    if (boundsField != null && stateField != null && restoredField != null)
                    {
                        var restoredBounds = (Rectangle)restoredField.GetValue(this)!;
                        var section = (BitVector32.Section)boundsField.GetValue(this)!;
                        var vector = (BitVector32)stateField.GetValue(this)!;
                        if (vector[section] == 1)
                        {
                            width = restoredBounds.Width;
                            height = restoredBounds.Height;
                        }
                    }
                }
            }

            return new Size(width, height);
        }
    }
}