1237 lines
49 KiB
C#

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);
}
}
/// <summary>
/// Calculates the size of non-client area of the control.
/// </summary>
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;
/// <summary>
/// Paints the non-client area of the control.
/// </summary>
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;
}
/// <summary>
/// Draws the non-client area buffered.
/// </summary>
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
{
/// <summary>
/// Calls base WndProc implementation
/// </summary>
/// <param name="m">Describes Windows Message</param>
void BaseWndProc(ref Message m);
/// <summary>
/// Gets the ItemPaintArgs which provide information for rendering.
/// </summary>
/// <param name="g">Reference to Canvas</param>
/// <returns>Returns the new ItemPaintArgs instance</returns>
ItemPaintArgs GetItemPaintArgs(Graphics g);
/// <summary>
/// Gets the reference to the BorderStyle used by the control if any.
/// </summary>
ElementStyle BorderStyle { get; }
/// <summary>
/// Paints the background of the control
/// </summary>
/// <param name="e">PaintEventArgs arguments</param>
void PaintBackground(PaintEventArgs e);
/// <summary>
/// Returns the Windows handle associated with the control.
/// </summary>
IntPtr Handle { get; }
/// <summary>
/// Returns width of the control.
/// </summary>
int Width { get; }
/// <summary>
/// Returns the height of the control.
/// </summary>
int Height { get; }
/// <summary>
/// Returns whether handled for the control has been created.
/// </summary>
bool IsHandleCreated { get; }
/// <summary>
/// Converts the client point into the screen point.
/// </summary>
/// <param name="client">Client point</param>
/// <returns>Client point converted into screen coordinates.</returns>
Point PointToScreen(Point client);
/// <summary>
/// Returns background color of the control.
/// </summary>
Color BackColor { get; }
/// <summary>
/// Returns background color of the control when Enabled=false.
/// </summary>
Color DisabledBackColor { get; }
/// <summary>
/// Returns whether control is enabled.
/// </summary>
bool Enabled { get; set; }
/// <summary>
/// Adjusts the client rectangle for the control.
/// </summary>
/// <param name="r">Reference to new client rectangle.</param>
void AdjustClientRectangle(ref Rectangle r);
/// <summary>
/// Adjusts the border rectangle before the non-client border is rendered.
/// </summary>
/// <param name="r">Border rectangle</param>
void AdjustBorderRectangle(ref Rectangle r);
/// <summary>
/// Occurs after non-client area is rendered and provides opportunity to render on top of it.
/// </summary>
/// <param name="g">Reference to Graphics object.</param>
void RenderNonClient(Graphics g);
}
}