using System;
using System.Text;
using System.Windows.Forms;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Runtime.InteropServices;
using DevComponents.DotNetBar.ScrollBar;
namespace DevComponents.DotNetBar.Controls
{
    internal class NonClientPaintHandler : ISkinHook
    {
        #region Private Variables
        private INonClientControl m_Control = null;
        private Rectangle m_ClientRectangle = Rectangle.Empty;
        private ScrollBarCore m_VScrollBar = null;
        private ScrollBarCore m_HScrollBar = null;
        private const int HC_ACTION = 0;
        private eScrollBarSkin m_SkinScrollbars = eScrollBarSkin.Optimized;
        private bool m_SuspendPaint = false;
        private bool m_IsVista = false;
        private bool m_IsListView = false;
        private bool m_IsAppScrollBarStyle = false;
        #endregion
        #region Events
        public event CustomNCPaintEventHandler BeforeBorderPaint;
        public event CustomNCPaintEventHandler AfterBorderPaint;
        #endregion
        #region Internal Implementation
        public bool IsAppScrollBarStyle
        {
            get { return m_IsAppScrollBarStyle; }
            set { m_IsAppScrollBarStyle = value; }
        }
        public NonClientPaintHandler(INonClientControl c, eScrollBarSkin skinScrollbars)
        {
            m_IsVista = System.Environment.OSVersion.Version.Major >= 6;
            //#if DEBUG
            //            m_IsVista = false;
            //#endif
            m_SkinScrollbars = skinScrollbars;
            m_Control = c;
            if (m_Control is Control)
            {
                ((Control)m_Control).HandleCreated += new EventHandler(Control_HandleCreated);
                ((Control)m_Control).HandleDestroyed += new EventHandler(Control_HandleDestroyed);
            }
            m_IsListView = m_Control is ListView;
            if (ShouldSkinScrollbars)
            {
                CreateScrollbars();
            }
            if (m_Control.IsHandleCreated && ShouldSkinScrollbars)
                RegisterHook();
        }
        private bool ShouldSkinScrollbars
        {
            get { return m_SkinScrollbars != eScrollBarSkin.None && !m_IsVista; }
        }
        public void Dispose()
        {
            UnRegisterHook();
        }
        private void CreateScrollbars()
        {
            m_VScrollBar = new ScrollBarCore(m_Control as Control, true);
            m_VScrollBar.IsAppScrollBarStyle = m_IsAppScrollBarStyle;
            m_HScrollBar = new ScrollBarCore(m_Control as Control, true);
            m_HScrollBar.IsAppScrollBarStyle = m_IsAppScrollBarStyle;
            m_HScrollBar.Orientation = eOrientation.Horizontal;
            m_HScrollBar.Enabled = false;
        }
        public bool SuspendPaint
        {
            get { return m_SuspendPaint; }
            set { m_SuspendPaint = value; }
        }
        public eScrollBarSkin SkinScrollbars
        {
            get { return m_SkinScrollbars; }
            set
            {
                if (m_SkinScrollbars != value)
                {
                    if (m_SkinScrollbars != eScrollBarSkin.None)
                    {
                        if (m_VScrollBar != null)
                        {
                            m_VScrollBar.Dispose();
                            m_VScrollBar = null;
                        }
                        if (m_HScrollBar != null)
                        {
                            m_HScrollBar.Dispose();
                            m_HScrollBar = null;
                        }
                        UnRegisterHook();
                    }
                    m_SkinScrollbars = value;
                    if (ShouldSkinScrollbars)
                    {
                        CreateScrollbars();
                        if (m_Control.IsHandleCreated)
                            RegisterHook();
                    }
                }
            }
        }
        private void Control_HandleDestroyed(object sender, EventArgs e)
        {
            UnRegisterHook();
        }
        private void Control_HandleCreated(object sender, EventArgs e)
        {
            if (ShouldSkinScrollbars)
                RegisterHook();
        }
        private void RegisterHook()
        {
            UpdateScrollValues();
            NonClientHook.RegisterHook(this);
        }
        private void UnRegisterHook()
        {
            if (ShouldSkinScrollbars)
                NonClientHook.UnregisterHook(this);
        }
        public Rectangle ClientRectangle
        {
            get { return m_ClientRectangle; }
        }
        public virtual bool WndProc(ref Message m)
        {
            bool callBase = true;
            switch (m.Msg)
            {
                case (int)WinApi.WindowsMessages.WM_NCPAINT:
                    {
                        callBase = WindowsMessageNCPaint(ref m);
                        break;
                    }
                case (int)WinApi.WindowsMessages.WM_CTLCOLORSCROLLBAR:
                    {
                        PaintNonClientAreaBuffered();
                        callBase = false;
                        break;
                    }
                case (int)WinApi.WindowsMessages.WM_NCCALCSIZE:
                    {
                        callBase = WindowsMessageNCCalcSize(ref m);
                        break;
                    }
                case (int)WinApi.WindowsMessages.WM_VSCROLL:
                    {
                        callBase = WindowsMessageVScroll(ref m);
                        break;
                    }
                case (int)WinApi.WindowsMessages.WM_HSCROLL:
                    {
                        callBase = WindowsMessageHScroll(ref m);
                        break;
                    }
                case (int)WinApi.WindowsMessages.SBM_SETPOS:
                    {
                        callBase = WindowsMessageSbmSetPos(ref m);
                        break;
                    }
                case (int)WinApi.WindowsMessages.WM_ERASEBKGND:
                    {
                        callBase = WindowsMessageEraseBkgnd(ref m);
                        break;
                    }
                case (int)WinApi.WindowsMessages.EM_GETMODIFY:
                    {
                        callBase = WindowsMessageEmGetModify(ref m);
                        break;
                    }
                case (int)WinApi.WindowsMessages.WM_NCLBUTTONDOWN:
                    {
                        callBase = WindowsMessageNcLButtonDown(ref m);
                        break;
                    }
                case (int)WinApi.WindowsMessages.WM_NCLBUTTONUP:
                    {
                        callBase = WindowsMessageNcLButtonUp(ref m);
                        break;
                    }
                case (int)WinApi.WindowsMessages.WM_NCMOUSELEAVE:
                    {
                        callBase = WindowsMessageNcMouseLeave(ref m);
                        break;
                    }
                case (int)WinApi.WindowsMessages.WM_NCMOUSEMOVE:
                    {
                        callBase = WindowsMessageNcMouseMove(ref m);
                        break;
                    }
                case (int)WinApi.WindowsMessages.WM_MOUSEWHEEL:
                    {
                        callBase = WindowsMessageMouseWheel(ref m);
                        break;
                    }
                case (int)WinApi.WindowsMessages.WM_SIZE:
                    {
                        callBase = WindowsMessageSize(ref m);
                        break;
                    }
                case (int)WinApi.WindowsMessages.WM_COMMAND:
                    {
                        if (WinApi.HIWORD(m.WParam) == 0x100)
                        {
                            CallBaseWndProcAndPaint(ref m);
                            callBase = false;
                        }
                        break;
                    }
                case (int)WinApi.WindowsMessages.WM_CTLCOLORBTN:
                    {
                        CallBaseWndProcAndPaint(ref m);
                        callBase = false;
                        break;
                    }
                case 0x120:
                    {
                        WindowsMessageCustomNotify(ref m);
                        callBase = false;
                        break;
                    }
            }
            return callBase;
        }
        private bool WindowsMessageSize(ref Message m)
        {
            if (m_IsListView)
            {
                CallBaseWndProcAndPaint(ref m);
                return false;
            }
            return true;
        }
        private void WindowsMessageCustomNotify(ref Message m)
        {
            int wParamInt = WinApi.ToInt(m.WParam);
            if (wParamInt == 0)
            {
                PaintNonClientAreaBuffered();
            }
            else if (wParamInt == 1)
            {
                Point p = ScreenToNonClientPoint(Control.MousePosition);
                if (m_VScrollBar.Visible)
                {
                    if (m_VScrollBar.IsMouseDown)
                        m_VScrollBar.MouseUp(new MouseEventArgs(MouseButtons.Left, 0, p.X, p.Y, 0));
                    else if (!m_VScrollBar.DisplayRectangle.Contains(p))
                        m_VScrollBar.MouseLeave();
                }
                if (m_HScrollBar.Visible)
                {
                    if (m_HScrollBar.IsMouseDown)
                        m_HScrollBar.MouseUp(new MouseEventArgs(MouseButtons.Left, 0, p.X, p.Y, 0));
                    else if (!m_HScrollBar.DisplayRectangle.Contains(p))
                        m_HScrollBar.MouseLeave();
                }
                PaintNonClientAreaBuffered();
            }
        }
        private bool WindowsMessageMouseWheel(ref Message m)
        {
            CallBaseWndProcAndPaint(ref m);
            return false;
        }
        private bool WindowsMessageNcMouseLeave(ref Message m)
        {
            if (!ShouldSkinScrollbars) return true;
            if (m_VScrollBar.Visible)
                m_VScrollBar.MouseLeave();
            if (m_HScrollBar.Visible)
                m_HScrollBar.MouseLeave();
            CallBaseWndProcAndPaint(ref m);
            return false;
        }
        private bool WindowsMessageNcMouseMove(ref Message m)
        {
            if (!ShouldSkinScrollbars) return true;
            Point p = ScreenToNonClientPoint(new Point(WinApi.LOWORD(m.LParam), WinApi.HIWORD(m.LParam)));
            if (m_VScrollBar.Visible)
                m_VScrollBar.MouseMove(new MouseEventArgs(Control.MouseButtons, 0, p.X, p.Y, 0));
            if (m_HScrollBar.Visible)
                m_HScrollBar.MouseMove(new MouseEventArgs(Control.MouseButtons, 0, p.X, p.Y, 0));
            CallBaseWndProcAndPaint(ref m);
            return false;
        }
        private bool WindowsMessageNcLButtonUp(ref Message m)
        {
            if (!ShouldSkinScrollbars) return true;
            Point p = ScreenToNonClientPoint(new Point(WinApi.LOWORD(m.LParam), WinApi.HIWORD(m.LParam)));
            if (m_VScrollBar.Visible)
                m_VScrollBar.MouseUp(new MouseEventArgs(MouseButtons.Left, 0, p.X, p.Y, 0));
            if (m_HScrollBar.Visible)
                m_HScrollBar.MouseUp(new MouseEventArgs(MouseButtons.Left, 0, p.X, p.Y, 0));
            CallBaseWndProcAndPaint(ref m);
            return false;
        }
        private bool WindowsMessageNcLButtonDown(ref Message m)
        {
            if (!ShouldSkinScrollbars) return true;
            Point p = ScreenToNonClientPoint(new Point(WinApi.LOWORD(m.LParam), WinApi.HIWORD(m.LParam)));
            if (m_VScrollBar.Visible)
                m_VScrollBar.MouseDown(new MouseEventArgs(MouseButtons.Left, 0, p.X, p.Y, 0));
            if (m_HScrollBar.Visible)
                m_HScrollBar.MouseDown(new MouseEventArgs(MouseButtons.Left, 0, p.X, p.Y, 0));
            CallBaseWndProcAndPaint(ref m);
            return false;
        }
        private bool WindowsMessageEmGetModify(ref Message m)
        {
            if (!ShouldSkinScrollbars) return true;
            CallBaseWndProcAndPaint(ref m);
            return false;
        }
        private bool WindowsMessageEraseBkgnd(ref Message m)
        {
            if (!m_IsListView || !ShouldSkinScrollbars) return true;
            CallBaseWndProcAndPaint(ref m);
            return false;
        }
        private void WindowsMessageMouseMove(IntPtr hWnd, Point mousePosition)
        {
            if (Control.MouseButtons == MouseButtons.Left && hWnd == m_Control.Handle && ShouldSkinScrollbars)
            {
                WinApi.PostMessage(hWnd, 0x120, IntPtr.Zero, IntPtr.Zero);
            }
        }
        private bool WindowsMessageSbmSetPos(ref Message m)
        {
            if (!ShouldSkinScrollbars) return true;
            CallBaseWndProcAndPaint(ref m);
            return false;
        }
        private void CallBaseWndProcAndPaintWndStyle(ref Message m)
        {
            const int WS_VISIBLE = 0x10000000;
            IntPtr style = WinApi.GetWindowLongPtr(m_Control.Handle, (int)WinApi.GWL.GWL_STYLE);
            IntPtr newStyle;
            if (IntPtr.Size == 8)
            {
                long ns = style.ToInt64();
                newStyle = new IntPtr(ns & ~(ns & WS_VISIBLE));
            }
            else
            {
                int ns = WinApi.ToInt(style);
                newStyle = new IntPtr(ns & ~(ns & WS_VISIBLE));
            }
            WinApi.SetWindowLongPtr(m_Control.Handle, (int)WinApi.GWL.GWL_STYLE, newStyle);
            //PaintUnBuffered();
            using (BufferedBitmap bmp = GetNonClientAreaBitmap())
            {
                ((INonClientControl)m_Control).BaseWndProc(ref m);
                WinApi.SetWindowLongPtr(m_Control.Handle, (int)WinApi.GWL.GWL_STYLE, style);
                RenderNonClientAreaBitmap(bmp);
            }
            if (m_Control is Control)
                ((Control)m_Control).Invalidate(true);
        }
        private bool WindowsMessageVScroll(ref Message m)
        {
            if (!ShouldSkinScrollbars) return true;
            if (m_SkinScrollbars == eScrollBarSkin.Optimized)
                CallBaseWndProcAndPaintWndStyle(ref m);
            else
                CallBaseWndProcAndPaint(ref m);
            return false;
        }
        private bool WindowsMessageHScroll(ref Message m)
        {
            if (!ShouldSkinScrollbars) return true;
            if (m_SkinScrollbars == eScrollBarSkin.Optimized)
                CallBaseWndProcAndPaintWndStyle(ref m);
            else
                CallBaseWndProcAndPaint(ref m);
            return false;
        }
        private void CallBaseWndProcAndPaint(ref Message m)
        {
            //PaintUnBuffered();
            using (BufferedBitmap bmp = GetNonClientAreaBitmap())
            {
                ((INonClientControl)m_Control).BaseWndProc(ref m);
                RenderNonClientAreaBitmap(bmp);
            }
        }
        /// 
        /// Calculates the size of non-client area of the control.
        /// 
        protected virtual bool WindowsMessageNCCalcSize(ref Message m)
        {
            ElementStyle style = ((INonClientControl)m_Control).BorderStyle;
            if (style != null && style.PaintBorder)
            {
                ((INonClientControl)m_Control).BaseWndProc(ref m);
                if (m.WParam == IntPtr.Zero)
                {
                    WinApi.RECT r = (WinApi.RECT)Marshal.PtrToStructure(m.LParam, typeof(WinApi.RECT));
                    Rectangle rc = GetClientRectangleForBorderStyle(r.ToRectangle(), style);
                    WinApi.RECT newClientRect = WinApi.RECT.FromRectangle(rc);
                    Marshal.StructureToPtr(newClientRect, m.LParam, false);
                    // Store the client rectangle in Window coordinates non-client coordinates
                    m_ClientRectangle = rc;
                    m_ClientRectangle.X = m_ClientRectangle.X - r.Left;
                    m_ClientRectangle.Y = m_ClientRectangle.Y - r.Top;
                }
                else
                {
                    WinApi.NCCALCSIZE_PARAMS csp;
                    csp = (WinApi.NCCALCSIZE_PARAMS)Marshal.PtrToStructure(m.LParam, typeof(WinApi.NCCALCSIZE_PARAMS));
                    WinApi.WINDOWPOS pos = (WinApi.WINDOWPOS)Marshal.PtrToStructure(csp.lppos, typeof(WinApi.WINDOWPOS));
                    WinApi.RECT rgrc0 = csp.rgrc0;
                    WinApi.RECT newClientRect = WinApi.RECT.FromRectangle(GetClientRectangleForBorderStyle(new Rectangle(rgrc0.Left, rgrc0.Top, rgrc0.Width, rgrc0.Height), style));
                    csp.rgrc0 = newClientRect;
                    csp.rgrc1 = newClientRect;
                    Marshal.StructureToPtr(csp, m.LParam, false);
                    // Store the client rectangle in Window coordinates non-client coordinates
                    m_ClientRectangle = csp.rgrc0.ToRectangle();
                    m_ClientRectangle.X = m_ClientRectangle.X - pos.x;
                    m_ClientRectangle.Y = m_ClientRectangle.Y - pos.y;
                }
            }
            else
            {
                // Take client rectangle directly
                if (m.WParam == IntPtr.Zero)
                {
                    WinApi.RECT rWindow = (WinApi.RECT)Marshal.PtrToStructure(m.LParam, typeof(WinApi.RECT));
                    ((INonClientControl)m_Control).BaseWndProc(ref m);
                    WinApi.RECT r = (WinApi.RECT)Marshal.PtrToStructure(m.LParam, typeof(WinApi.RECT));
                    WinApi.RECT newClientRect = WinApi.RECT.FromRectangle(GetClientRectangleForBorderStyle(new Rectangle(r.Left, r.Top, r.Width, r.Height), style));
                    Marshal.StructureToPtr(newClientRect, m.LParam, false);
                    // Store the client rectangle in Window coordinates non-client coordinates
                    m_ClientRectangle = newClientRect.ToRectangle();
                    m_ClientRectangle.X = m_ClientRectangle.X - rWindow.Left;
                    m_ClientRectangle.Y = m_ClientRectangle.Y - rWindow.Top;
                }
                else
                {
                    ((INonClientControl)m_Control).BaseWndProc(ref m);
                    WinApi.NCCALCSIZE_PARAMS csp;
                    csp = (WinApi.NCCALCSIZE_PARAMS)Marshal.PtrToStructure(m.LParam, typeof(WinApi.NCCALCSIZE_PARAMS));
                    WinApi.WINDOWPOS pos = (WinApi.WINDOWPOS)Marshal.PtrToStructure(csp.lppos, typeof(WinApi.WINDOWPOS));
                    WinApi.RECT rgrc0 = csp.rgrc0;
                    WinApi.RECT newClientRect = WinApi.RECT.FromRectangle(GetClientRectangleForBorderStyle(new Rectangle(rgrc0.Left, rgrc0.Top, rgrc0.Width, rgrc0.Height), style));
                    csp.rgrc0 = newClientRect;
                    Marshal.StructureToPtr(csp, m.LParam, false);
                    // Store the client rectangle in Window coordinates non-client coordinates
                    m_ClientRectangle = csp.rgrc0.ToRectangle();
                    m_ClientRectangle.X = m_ClientRectangle.X - pos.x;
                    m_ClientRectangle.Y = m_ClientRectangle.Y - pos.y;
                }
            }
            return false;
        }
        internal int GetLeftBorderWidth(ElementStyle style)
        {
            if (style.PaintLeftBorder)
            {
                int w = style.BorderLeftWidth;
                if (style.CornerTypeTopLeft == eCornerType.Rounded || style.CornerTypeTopLeft == eCornerType.Diagonal
                    || style.CornerTypeBottomLeft == eCornerType.Rounded || style.CornerTypeBottomLeft == eCornerType.Diagonal ||
                    (style.CornerType == eCornerType.Rounded || style.CornerType == eCornerType.Diagonal) &&
                    (style.CornerTypeTopLeft == eCornerType.Inherit || style.CornerTypeBottomLeft == eCornerType.Inherit))
                    w = Math.Max(w, style.CornerDiameter / 2 + 1);
                return w;
            }
            return 0;
        }
        internal int GetTopBorderWidth(ElementStyle style)
        {
            if (style.PaintTopBorder)
            {
                int w = style.BorderTopWidth;
                if (style.CornerTypeTopLeft == eCornerType.Rounded || style.CornerTypeTopLeft == eCornerType.Diagonal
                    || style.CornerTypeTopRight == eCornerType.Rounded || style.CornerTypeTopRight == eCornerType.Diagonal ||
                    (style.CornerType == eCornerType.Rounded || style.CornerType == eCornerType.Diagonal) &&
                    (style.CornerTypeTopLeft == eCornerType.Inherit || style.CornerTypeTopRight == eCornerType.Inherit))
                    w = Math.Max(w, style.CornerDiameter / 2 + 1);
                return w;
            }
            return 0;
        }
        internal int GetRightBorderWidth(ElementStyle style)
        {
            if (style.PaintRightBorder)
            {
                int w = style.BorderRightWidth;
                if (style.CornerTypeTopRight == eCornerType.Rounded || style.CornerTypeBottomRight == eCornerType.Rounded
                    || style.CornerTypeTopRight == eCornerType.Diagonal || style.CornerTypeBottomRight == eCornerType.Diagonal ||
                    (style.CornerType == eCornerType.Rounded || style.CornerType == eCornerType.Diagonal) &&
                    (style.CornerTypeTopRight == eCornerType.Inherit || style.CornerTypeBottomRight == eCornerType.Inherit))
                    w = Math.Max(w, style.CornerDiameter / 2 + 1);
                return w;
            }
            return 0;
        }
        internal int GetBottomBorderWidth(ElementStyle style)
        {
            if (style.PaintBottomBorder)
            {
                int w = style.BorderBottomWidth;
                if (style.CornerTypeBottomLeft == eCornerType.Rounded || style.CornerTypeBottomRight == eCornerType.Rounded ||
                    style.CornerTypeBottomLeft == eCornerType.Diagonal || style.CornerTypeBottomRight == eCornerType.Diagonal ||
                    (style.CornerType == eCornerType.Rounded || style.CornerType == eCornerType.Diagonal) &&
                    (style.CornerTypeBottomLeft == eCornerType.Inherit || style.CornerTypeBottomRight == eCornerType.Inherit))
                    w = Math.Max(w, style.CornerDiameter / 2 + 1);
                return w;
            }
            return 0;
        }
        internal Rectangle GetClientRectangleForBorderStyle(Rectangle rect, ElementStyle style)
        {
            if (style == null)
                return rect;
            if (style.PaintLeftBorder)
            {
                int w = GetLeftBorderWidth(style);
                rect.X += w;
                rect.Width -= w;
            }
            if (style.PaintTopBorder)
            {
                int w = GetTopBorderWidth(style);
                rect.Y += w;
                rect.Height -= w;
            }
            if (style.PaintRightBorder)
            {
                int w = GetRightBorderWidth(style);
                rect.Width -= w;
            }
            if (style.PaintBottomBorder)
            {
                int w = GetBottomBorderWidth(style);
                rect.Height -= w;
            }
            TextBox tb = m_Control as TextBox;
            if (tb != null && tb.Multiline && tb.ScrollBars != ScrollBars.None)
            {
                if (tb.ScrollBars == ScrollBars.Vertical || tb.ScrollBars == ScrollBars.Both)
                {
                    if (tb.RightToLeft == RightToLeft.Yes)
                        rect.Width -= style.PaddingRight;
                    else
                    {
                        rect.X += style.PaddingLeft;
                        rect.Width -= style.PaddingLeft;
                    }
                }
                return rect;
            }
            rect.X += style.PaddingLeft;
            rect.Width -= style.PaddingLeft + style.PaddingRight;
            rect.Y += style.PaddingTop;
            //rect.Height -= style.PaddingTop + ((m_Control is TextBox)? 0 : style.PaddingBottom);
            rect.Height -= style.PaddingTop + style.PaddingBottom;
            m_Control.AdjustClientRectangle(ref rect);
            return rect;
        }
        private bool m_Painting = false;
        /// 
        /// Paints the non-client area of the control.
        /// 
        protected virtual bool WindowsMessageNCPaint(ref Message m)
        {
            if (!ShouldSkinScrollbars)
            {
                ((INonClientControl)m_Control).BaseWndProc(ref m);
                if (m_Control.IsHandleCreated && m_Control.Handle != IntPtr.Zero)
                    PaintNonClientAreaBuffered();
                return false;
            }
            //PaintUnBuffered();
            using (BufferedBitmap bmp = GetNonClientAreaBitmap())
            {
                ((INonClientControl)m_Control).BaseWndProc(ref m);
                RenderNonClientAreaBitmap(bmp);
            }
            m.Result = IntPtr.Zero;
            //if (m_Control.IsHandleCreated && m_Control.Handle != IntPtr.Zero)
            //{
            //    PaintNonClientAreaBuffered();
            //}
            return false;
        }
        /// 
        /// Draws the non-client area buffered.
        /// 
        public void PaintNonClientAreaBuffered()
        {
            //PaintUnBuffered();
            if (m_Control.Width <= 0 || m_Control.Height <= 0 || m_SuspendPaint) return;
            using (BufferedBitmap bmp = GetNonClientAreaBitmap())
            {
                RenderNonClientAreaBitmap(bmp);
            }
        }
        //private Bitmap GetNonClientAreaBitmap()
        //{
        //    if (m_Control.Width <= 0 || m_Control.Height <= 0 || m_SuspendPaint || !m_Control.IsHandleCreated) return null;
        //    Bitmap bmp = new Bitmap(m_Control.Width, m_Control.Height);
        //    using (Graphics g = Graphics.FromImage(bmp))
        //    {
        //        PaintNonClientArea(g);
        //    }
        //    return bmp;
        //}
        private BufferedBitmap GetNonClientAreaBitmap()
        {
            if (m_Control.Width <= 0 || m_Control.Height <= 0 || m_SuspendPaint || !m_Control.IsHandleCreated) return null;
            BufferedBitmap bmp = null;
            IntPtr hdc = WinApi.GetWindowDC(m_Control.Handle);
            if (hdc == IntPtr.Zero) return null;
            Rectangle r = GetControlRectangle();
            try
            {
                bmp = new BufferedBitmap(hdc, new Rectangle(0, 0, r.Width, r.Height));
                PaintNonClientArea(bmp.Graphics);
            }
            finally
            {
                WinApi.ReleaseDC(m_Control.Handle, hdc);
            }
            return bmp;
        }
        //private void PaintUnBuffered()
        //{
        //    IntPtr dc = WinApi.GetWindowDC(m_Control.Handle);
        //    try
        //    {
        //        using (Graphics g = Graphics.FromHdc(dc))
        //        {
        //            g.SetClip(GetClientRectangle(), CombineMode.Exclude);
        //            if (!ShouldSkinScrollbars)
        //            {
        //                WinApi.SCROLLBARINFO psbi = new WinApi.SCROLLBARINFO();
        //                psbi.cbSize = Marshal.SizeOf(psbi);
        //                WinApi.GetScrollBarInfo(m_Control.Handle, (uint)WinApi.eObjectId.OBJID_VSCROLL, ref psbi);
        //                if (psbi.rgstate[0] != (int)WinApi.eStateFlags.STATE_SYSTEM_INVISIBLE)
        //                {
        //                    Rectangle rvs = ScreenToNonClientRectangle(psbi.rcScrollBar.ToRectangle());
        //                    g.SetClip(rvs, System.Drawing.Drawing2D.CombineMode.Exclude);
        //                }
        //                psbi = new WinApi.SCROLLBARINFO();
        //                psbi.cbSize = Marshal.SizeOf(psbi);
        //                WinApi.GetScrollBarInfo(m_Control.Handle, (uint)WinApi.eObjectId.OBJID_HSCROLL, ref psbi);
        //                if (psbi.rgstate[0] != (int)WinApi.eStateFlags.STATE_SYSTEM_INVISIBLE)
        //                {
        //                    Rectangle rvs = ScreenToNonClientRectangle(psbi.rcScrollBar.ToRectangle());
        //                    g.SetClip(rvs, System.Drawing.Drawing2D.CombineMode.Exclude);
        //                }
        //            }
        //            PaintNonClientArea(g);
        //            g.ResetClip();
        //        }
        //    }
        //    finally
        //    {
        //        WinApi.ReleaseDC(m_Control.Handle, dc);
        //    }
        //}
        private void RenderNonClientAreaBitmap(BufferedBitmap bmp)
        {
            if (bmp == null) return;
            IntPtr dc = WinApi.GetWindowDC(m_Control.Handle);
            try
            {
                using (Graphics g = Graphics.FromHdc(dc))
                {
                    Rectangle[] clips = new Rectangle[3];
                    clips[0] = GetClientRectangle();
                    if (!ShouldSkinScrollbars)
                    {
                        WinApi.SCROLLBARINFO psbi = new WinApi.SCROLLBARINFO();
                        psbi.cbSize = Marshal.SizeOf(psbi);
                        WinApi.GetScrollBarInfo(m_Control.Handle, (uint)WinApi.eObjectId.OBJID_VSCROLL, ref psbi);
                        if (psbi.rgstate[0] != (int)WinApi.eStateFlags.STATE_SYSTEM_INVISIBLE)
                        {
                            Rectangle rvs = ScreenToNonClientRectangle(psbi.rcScrollBar.ToRectangle());
                            clips[1] = rvs;
                        }
                        psbi = new WinApi.SCROLLBARINFO();
                        psbi.cbSize = Marshal.SizeOf(psbi);
                        WinApi.GetScrollBarInfo(m_Control.Handle, (uint)WinApi.eObjectId.OBJID_HSCROLL, ref psbi);
                        if (psbi.rgstate[0] != (int)WinApi.eStateFlags.STATE_SYSTEM_INVISIBLE)
                        {
                            Rectangle rvs = ScreenToNonClientRectangle(psbi.rcScrollBar.ToRectangle());
                            clips[2] = rvs;
                        }
                    }
                    bmp.Render(g, clips);
                }
            }
            finally
            {
                WinApi.ReleaseDC(m_Control.Handle, dc);
            }
        }
        //private void RenderNonClientAreaBitmap(Bitmap bmp)
        //{
        //    if (bmp == null) return;
        //    IntPtr dc = WinApi.GetWindowDC(m_Control.Handle);
        //    try
        //    {
        //        using (Graphics g = Graphics.FromHdc(dc))
        //        {
        //            g.SetClip(GetClientRectangle(), CombineMode.Exclude);
        //            if (!ShouldSkinScrollbars)
        //            {
        //                WinApi.SCROLLBARINFO psbi = new WinApi.SCROLLBARINFO();
        //                psbi.cbSize = Marshal.SizeOf(psbi);
        //                WinApi.GetScrollBarInfo(m_Control.Handle, (uint)WinApi.eObjectId.OBJID_VSCROLL, ref psbi);
        //                if (psbi.rgstate[0] != (int)WinApi.eStateFlags.STATE_SYSTEM_INVISIBLE)
        //                {
        //                    Rectangle rvs = ScreenToNonClientRectangle(psbi.rcScrollBar.ToRectangle());
        //                    g.SetClip(rvs, System.Drawing.Drawing2D.CombineMode.Exclude);
        //                }
        //                psbi = new WinApi.SCROLLBARINFO();
        //                psbi.cbSize = Marshal.SizeOf(psbi);
        //                WinApi.GetScrollBarInfo(m_Control.Handle, (uint)WinApi.eObjectId.OBJID_HSCROLL, ref psbi);
        //                if (psbi.rgstate[0] != (int)WinApi.eStateFlags.STATE_SYSTEM_INVISIBLE)
        //                {
        //                    Rectangle rvs = ScreenToNonClientRectangle(psbi.rcScrollBar.ToRectangle());
        //                    g.SetClip(rvs, System.Drawing.Drawing2D.CombineMode.Exclude);
        //                }
        //            }
        //            g.DrawImageUnscaled(bmp, 0, 0);
        //            g.ResetClip();
        //        }
        //    }
        //    finally
        //    {
        //        WinApi.ReleaseDC(m_Control.Handle, dc);
        //    }
        //}
        //protected virtual void PaintNonClientAreaBuffered(Graphics targetGraphics)
        //{
        //    Bitmap bmp = new Bitmap(m_Control.Width, m_Control.Height);
        //    try
        //    {
        //        using (Graphics g = Graphics.FromImage(bmp))
        //        {
        //            PaintNonClientArea(g);
        //        }
        //        targetGraphics.SetClip(GetClientRectangle(), CombineMode.Exclude);
        //        if (!m_SkinScrollbars)
        //        {
        //            WinApi.SCROLLBARINFO psbi = new WinApi.SCROLLBARINFO();
        //            psbi.cbSize = Marshal.SizeOf(psbi);
        //            WinApi.GetScrollBarInfo(m_Control.Handle, (uint)WinApi.eObjectId.OBJID_VSCROLL, ref psbi);
        //            if (psbi.rgstate[0] != (int)WinApi.eStateFlags.STATE_SYSTEM_INVISIBLE)
        //            {
        //                Rectangle rvs = ScreenToNonClientRectangle(psbi.rcScrollBar.ToRectangle());
        //                targetGraphics.SetClip(rvs, System.Drawing.Drawing2D.CombineMode.Exclude);
        //            }
        //            psbi = new WinApi.SCROLLBARINFO();
        //            psbi.cbSize = Marshal.SizeOf(psbi);
        //            WinApi.GetScrollBarInfo(m_Control.Handle, (uint)WinApi.eObjectId.OBJID_HSCROLL, ref psbi);
        //            if (psbi.rgstate[0] != (int)WinApi.eStateFlags.STATE_SYSTEM_INVISIBLE)
        //            {
        //                Rectangle rvs = ScreenToNonClientRectangle(psbi.rcScrollBar.ToRectangle());
        //                targetGraphics.SetClip(rvs, System.Drawing.Drawing2D.CombineMode.Exclude);
        //            }
        //        }
        //        targetGraphics.DrawImageUnscaled(bmp, 0, 0);
        //        targetGraphics.ResetClip();
        //    }
        //    finally
        //    {
        //        bmp.Dispose();
        //    }
        //}
        private Rectangle GetClientRectangle()
        {
            return m_ClientRectangle;
        }
        public void UpdateScrollValues()
        {
            if (!ShouldSkinScrollbars) return;
            WinApi.SCROLLBARINFO psbi = new WinApi.SCROLLBARINFO();
            psbi.cbSize = Marshal.SizeOf(psbi);
            WinApi.GetScrollBarInfo(m_Control.Handle, (uint)WinApi.eObjectId.OBJID_VSCROLL, ref psbi);
            if (psbi.rgstate[0] != (int)WinApi.eStateFlags.STATE_SYSTEM_INVISIBLE)
            {
                Rectangle displayRect = ScreenToNonClientRectangle(psbi.rcScrollBar.ToRectangle());
                if (m_VScrollBar.DisplayRectangle != displayRect)
                    m_VScrollBar.DisplayRectangle = displayRect;
                Rectangle thumbRect = new Rectangle(displayRect.X, displayRect.Y, displayRect.Width, psbi.dxyLineButton);
                if (m_VScrollBar.ThumbDecreaseRectangle != thumbRect)
                    m_VScrollBar.ThumbDecreaseRectangle = thumbRect;
                thumbRect = new Rectangle(displayRect.X, displayRect.Bottom - psbi.dxyLineButton, displayRect.Width, psbi.dxyLineButton);
                if (m_VScrollBar.ThumbIncreaseRectangle != thumbRect)
                    m_VScrollBar.ThumbIncreaseRectangle = thumbRect;
                thumbRect = new Rectangle(displayRect.X, displayRect.Y + psbi.xyThumbTop, displayRect.Width, psbi.xyThumbBottom - psbi.xyThumbTop);
                if (m_VScrollBar.TrackRectangle != thumbRect)
                    m_VScrollBar.TrackRectangle = thumbRect;
                if (psbi.rgstate[0] == (int)WinApi.eStateFlags.STATE_SYSTEM_UNAVAILABLE)
                {
                    if (m_VScrollBar.Enabled) m_VScrollBar.Enabled = false;
                }
                else if (!m_VScrollBar.Enabled)
                    m_VScrollBar.Enabled = true;
                m_VScrollBar.Visible = true;
            }
            else
                m_VScrollBar.Visible = false;
            // Horizontal scroll bar
            psbi = new WinApi.SCROLLBARINFO();
            psbi.cbSize = Marshal.SizeOf(psbi);
            WinApi.GetScrollBarInfo(m_Control.Handle, (uint)WinApi.eObjectId.OBJID_HSCROLL, ref psbi);
            if (psbi.rgstate[0] != (int)WinApi.eStateFlags.STATE_SYSTEM_INVISIBLE)
            {
                Rectangle displayRect = ScreenToNonClientRectangle(psbi.rcScrollBar.ToRectangle());
                if (m_HScrollBar.DisplayRectangle != displayRect)
                    m_HScrollBar.DisplayRectangle = displayRect;
                Rectangle thumbRect = new Rectangle(displayRect.X, displayRect.Y, psbi.dxyLineButton, displayRect.Height);
                if (m_HScrollBar.ThumbDecreaseRectangle != thumbRect)
                    m_HScrollBar.ThumbDecreaseRectangle = thumbRect;
                thumbRect = new Rectangle(displayRect.Right - psbi.dxyLineButton, displayRect.Y, psbi.dxyLineButton, displayRect.Height);
                if (m_HScrollBar.ThumbIncreaseRectangle != thumbRect)
                    m_HScrollBar.ThumbIncreaseRectangle = thumbRect;
                thumbRect = new Rectangle(displayRect.X + psbi.xyThumbTop, displayRect.Y, psbi.xyThumbBottom - psbi.xyThumbTop, displayRect.Height);
                if (m_HScrollBar.TrackRectangle != thumbRect)
                    m_HScrollBar.TrackRectangle = thumbRect;
                if (psbi.rgstate[0] == (int)WinApi.eStateFlags.STATE_SYSTEM_UNAVAILABLE)
                {
                    if (m_HScrollBar.Enabled) m_VScrollBar.Enabled = false;
                }
                else if (!m_HScrollBar.Enabled)
                    m_HScrollBar.Enabled = true;
                m_HScrollBar.Visible = true;
            }
            else
                m_HScrollBar.Visible = false;
        }
        protected virtual void PaintNonClientArea(Graphics g)
        {
            if (m_Painting) return;
            m_Painting = true;
            try
            {
                // Paint Background and border
                PaintBorder(g);
                if (ShouldSkinScrollbars)
                {
                    UpdateScrollValues();
                    if (m_VScrollBar.Visible)
                        m_VScrollBar.Paint(((INonClientControl)m_Control).GetItemPaintArgs(g));
                    if (m_HScrollBar.Visible)
                        m_HScrollBar.Paint(((INonClientControl)m_Control).GetItemPaintArgs(g));
                }
            }
            finally
            {
                m_Painting = false;
            }
        }
        private Rectangle GetControlRectangle()
        {
            if (m_Control.IsHandleCreated)
            {
                WinApi.RECT r = new WinApi.RECT();
                WinApi.GetWindowRect(m_Control.Handle, ref r);
                return new Rectangle(0, 0, r.Width, r.Height);
            }
            else
                return new Rectangle(0, 0, m_Control.Width, m_Control.Height);
        }
        private void PaintBorder(Graphics g)
        {
            ElementStyle style = ((INonClientControl)m_Control).BorderStyle;
            Rectangle r = GetControlRectangle();
            if (style == null || r.Width <= 0 || r.Height <= 0) return;
            ElementStyleDisplayInfo displayInfo = new ElementStyleDisplayInfo(style, g, r);
            if (style.BackColor == Color.Transparent && (style.BackColor2.IsEmpty || style.BackColor2 == Color.Transparent))
            {
                ((INonClientControl)m_Control).PaintBackground(new PaintEventArgs(g, r));
            }
            else
            {
                if (style.BackColor.IsEmpty && m_Control.BackColor != Color.Transparent)
                {
                    using (SolidBrush brush = new SolidBrush(GetBackColor()))
                        g.FillRectangle(brush, r);
                }
                else
                {
                    if (m_Control.BackColor == Color.Transparent || style.PaintBorder && (style.CornerType == eCornerType.Rounded || style.CornerType == eCornerType.Diagonal ||
                        style.CornerTypeBottomLeft == eCornerType.Rounded || style.CornerTypeBottomLeft == eCornerType.Diagonal ||
                        style.CornerTypeBottomRight == eCornerType.Rounded || style.CornerTypeBottomRight == eCornerType.Diagonal ||
                        style.CornerTypeTopLeft == eCornerType.Rounded || style.CornerTypeTopLeft == eCornerType.Diagonal ||
                        style.CornerTypeTopRight == eCornerType.Rounded || style.CornerTypeTopRight == eCornerType.Diagonal))
                    {
                        if (m_Control is TextBox || m_Control.BackColor == Color.Transparent)
                            ((INonClientControl)m_Control).PaintBackground(new PaintEventArgs(g, r));
                        else
                            using (SolidBrush brush = new SolidBrush(m_Control.BackColor))
                                g.FillRectangle(brush, r);
                    }
                    else
                    {
                        using (SolidBrush brush = new SolidBrush(m_Control.BackColor))
                            g.FillRectangle(brush, r);
                    }
                }
                Rectangle rback = r;
                if (style.PaintBorder)
                {
                    if (style.PaintRightBorder && style.BorderRightWidth > 1)
                        rback.Width--;
                    if (style.PaintBottomBorder && style.BorderBottomWidth > 1)
                        rback.Height--;
                }
                m_Control.AdjustBorderRectangle(ref rback);
                displayInfo.Bounds = rback;
                ElementStyleDisplay.PaintBackground(displayInfo);
                m_Control.RenderNonClient(g);
            }
            SmoothingMode sm = g.SmoothingMode;
            if (style.PaintBorder && (style.CornerType == eCornerType.Rounded || style.CornerType == eCornerType.Diagonal))
                g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
            m_Control.AdjustBorderRectangle(ref r);
            displayInfo.Bounds = r;
            this.BeforePaintBorder(g, r);
            ElementStyleDisplay.PaintBorder(displayInfo);
            g.SmoothingMode = sm;
            this.AfterPaintBorder(g, r);
        }
        private Color GetBackColor()
        {
            return (m_Control.Enabled ? m_Control.BackColor : (m_Control.DisabledBackColor.IsEmpty ? SystemColors.Control : m_Control.DisabledBackColor));
        }
        private void AfterPaintBorder(Graphics g, Rectangle r)
        {
            if (AfterBorderPaint != null)
                AfterBorderPaint(this, new CustomNCPaintEventArgs(g, r));
        }
        private void BeforePaintBorder(Graphics g, Rectangle r)
        {
            if (BeforeBorderPaint != null)
                BeforeBorderPaint(this, new CustomNCPaintEventArgs(g, r));
        }
        private Point ScreenToNonClientPoint(Point p)
        {
            Point pScreen = m_Control.PointToScreen(new Point(-m_ClientRectangle.X, -m_ClientRectangle.Y));
            p.X = p.X - pScreen.X;
            p.Y = p.Y - pScreen.Y;
            return p;
        }
        private Rectangle ScreenToNonClientRectangle(Rectangle r)
        {
            Point p = m_Control.PointToScreen(new Point(-m_ClientRectangle.X, -m_ClientRectangle.Y));
            r.X = r.X - p.X;
            r.Y = r.Y - p.Y;
            return r;
        }
        #endregion
        #region ISkinHook Members
        public delegate void InvokeMouseMethodDelegate(IntPtr handle, Point mousePos);
        public void PostMouseMove(IntPtr hWnd, Point mousePos)
        {
            if (m_Control is Control)
            {
                Control c = m_Control as Control;
                if (c == null || c.IsDisposed || !c.IsHandleCreated)
                    return;
                if (c.InvokeRequired)
                {
#if FRAMEWORK20
                    c.BeginInvoke(new InvokeMouseMethodDelegate(this.PostMouseMoveSafe), hWnd, mousePos);
#else
				c.BeginInvoke(new InvokeMouseMethodDelegate(this.PostMouseMoveSafe), new object[]{hWnd, mousePos});
#endif
                }
                else
                    this.PostMouseMoveSafe(hWnd, mousePos);
            }
            else
                PostMouseMoveSafe(hWnd, mousePos);
        }
        private void PostMouseMoveSafe(IntPtr hWnd, Point mousePos)
        {
            if (hWnd == m_Control.Handle)
                WindowsMessageMouseMove(hWnd, mousePos);
        }
        public void PostMouseUp(IntPtr hWnd, Point mousePos)
        {
            if (m_Control is Control)
            {
                Control c = m_Control as Control;
                if (c == null || c.IsDisposed || !c.IsHandleCreated)
                    return;
                if (c.InvokeRequired)
                {
#if FRAMEWORK20
                    c.BeginInvoke(new InvokeMouseMethodDelegate(this.PostMouseUpSafe), hWnd, mousePos);
#else
				c.BeginInvoke(new InvokeMouseMethodDelegate(this.PostMouseUpSafe), new object[] {hWnd, mousePos});
#endif
                }
                else
                {
                    this.PostMouseUpSafe(hWnd, mousePos);
                }
            }
            else
                PostMouseUpSafe(hWnd, mousePos);
        }
        public void PostMouseUpSafe(IntPtr hWnd, Point mousePos)
        {
            if (hWnd == m_Control.Handle && ShouldSkinScrollbars)
            {
                if (m_VScrollBar.IsMouseDown)
                    WinApi.PostMessage(m_Control.Handle, 0x120, (IntPtr)1, (IntPtr)0);
                else if (m_HScrollBar.IsMouseDown)
                    WinApi.PostMessage(m_Control.Handle, 0x120, (IntPtr)1, (IntPtr)0);
            }
        }
        #endregion
    }
    internal delegate void CustomNCPaintEventHandler(object sender, CustomNCPaintEventArgs e);
    internal class CustomNCPaintEventArgs : EventArgs
    {
        public Graphics Graphics = null;
        public Rectangle Bounds = Rectangle.Empty;
        public CustomNCPaintEventArgs(Graphics g, Rectangle r)
        {
            this.Graphics = g;
            this.Bounds = r;
        }
    }
    public interface INonClientControl
    {
        /// 
        /// Calls base WndProc implementation
        /// 
        /// Describes Windows Message
        void BaseWndProc(ref Message m);
        /// 
        /// Gets the ItemPaintArgs which provide information for rendering.
        /// 
        /// Reference to Canvas
        /// Returns the new ItemPaintArgs instance
        ItemPaintArgs GetItemPaintArgs(Graphics g);
        /// 
        /// Gets the reference to the BorderStyle used by the control if any.
        /// 
        ElementStyle BorderStyle { get; }
        /// 
        /// Paints the background of the control
        /// 
        /// PaintEventArgs arguments
        void PaintBackground(PaintEventArgs e);
        /// 
        /// Returns the Windows handle associated with the control.
        /// 
        IntPtr Handle { get; }
        /// 
        /// Returns width of the control.
        /// 
        int Width { get; }
        /// 
        /// Returns the height of the control.
        /// 
        int Height { get; }
        /// 
        /// Returns whether handled for the control has been created.
        /// 
        bool IsHandleCreated { get; }
        /// 
        /// Converts the client point into the screen point.
        /// 
        /// Client point
        /// Client point converted into screen coordinates.
        Point PointToScreen(Point client);
        /// 
        /// Returns background color of the control.
        /// 
        Color BackColor { get; }
        /// 
        /// Returns background color of the control when Enabled=false.
        /// 
        Color DisabledBackColor { get; }
        /// 
        /// Returns whether control is enabled.
        /// 
        bool Enabled { get; set; }
        /// 
        /// Adjusts the client rectangle for the control.
        /// 
        /// Reference to new client rectangle.
        void AdjustClientRectangle(ref Rectangle r);
        /// 
        /// Adjusts the border rectangle before the non-client border is rendered.
        /// 
        /// Border rectangle
        void AdjustBorderRectangle(ref Rectangle r);
        /// 
        /// Occurs after non-client area is rendered and provides opportunity to render on top of it.
        /// 
        /// Reference to Graphics object.
        void RenderNonClient(Graphics g);
    }
}