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); } }