using System; using System.Windows.Forms; using System.Text; using DevComponents.DotNetBar.ScrollBar; using System.Drawing; using DevComponents.DotNetBar.Rendering; using System.Runtime.InteropServices; namespace DevComponents.DotNetBar.Controls { internal class ScrollBarImplementation: IDisposable { #region Private Variables private System.Windows.Forms.ScrollBar m_ParentScrollBar = null; private ScrollBarCore m_ScrollBarCore = null; private bool m_FirstPaint = true; private int m_MouseDownTrackOffset = 0; private Timer m_PaintTimer = null; private bool m_IsVScrollBar = false; private IScrollBarExtender m_ParentScrollBarWndProc = null; private bool m_UseLockWindowUpdate = false; #endregion #region Constructor public ScrollBarImplementation(System.Windows.Forms.ScrollBar sb) { m_ParentScrollBar = sb; m_ParentScrollBarWndProc = (IScrollBarExtender)m_ParentScrollBar; m_IsVScrollBar = m_ParentScrollBar is VScrollBar; m_PaintTimer = new Timer(); m_PaintTimer.Interval = 50; m_PaintTimer.Tick += new EventHandler(PaintTimerTick); m_ScrollBarCore = new ScrollBarCore(m_ParentScrollBar, true); //m_ScrollBarCore.IsAppScrollBarStyle = false; if (m_ParentScrollBar is HScrollBar) m_ScrollBarCore.Orientation = eOrientation.Horizontal; else m_ScrollBarCore.Orientation = eOrientation.Vertical; m_ScrollBarCore.Minimum = m_ParentScrollBar.Minimum; m_ScrollBarCore.Maximum = m_ParentScrollBar.Maximum; m_ScrollBarCore.Value = m_ParentScrollBar.Value; } #endregion #region Internal Implementation internal void OnHandleCreated() { Themes.SetWindowTheme(m_ParentScrollBar.Handle, "", ""); UpdateScrollValues(); } internal bool WndProc(ref Message m) { if (m.Msg == (int)WinApi.WindowsMessages.SBM_SETSCROLLINFO || m.Msg == 0x2114 || m.Msg == 0x2115 || m.Msg == (int)WinApi.WindowsMessages.WM_MOUSEMOVE) { CallBaseWndProc(ref m); SendDelayPaintMessage(); return false; } else if (m.Msg == (int)WinApi.WindowsMessages.WM_SIZE) { CallBaseWndProc(ref m); m_FirstPaint = true; SendDelayPaintMessage(); return false; } else if (m.Msg == (int)WinApi.WindowsMessages.WM_ERASEBKGND) { //PaintUsingDC(); //m.Result = new IntPtr(1); return false; } else if (m.Msg == (int)WinApi.WindowsMessages.WM_LBUTTONDOWN) { Point p = new Point(WinApi.LOWORD(m.LParam), WinApi.HIWORD(m.LParam)); InternalMouseDown(new MouseEventArgs(GetMouseButton(m.WParam.ToInt32()), 0, p.X, p.Y, 0)); return false; } else if (m.Msg == (int)WinApi.WindowsMessages.WM_LBUTTONUP) { Point p = new Point(WinApi.LOWORD(m.LParam), WinApi.HIWORD(m.LParam)); InternalMouseUp(new MouseEventArgs(GetMouseButton(m.WParam.ToInt32()), 0, p.X, p.Y, 0)); return false; } else if (m.Msg == (int)WinApi.WindowsMessages.WM_LBUTTONDBLCLK) { Point p = new Point(WinApi.LOWORD(m.LParam), WinApi.HIWORD(m.LParam)); InternalMouseDoubleClick(new MouseEventArgs(GetMouseButton(m.WParam.ToInt32()), 0, p.X, p.Y, 0)); return false; } else if (m.Msg == NativeFunctions.WM_USER + 7) { PaintUsingDC(); } else if (m.Msg == (int)WinApi.WindowsMessages.WM_SYSTIMER) { if (m_ScrollBarCore.MouseOverPart == ScrollBarCore.eScrollPart.Track && Control.MouseButtons == MouseButtons.Left) { Point p = m_ParentScrollBar.PointToClient(Control.MousePosition); OnMouseMove(new MouseEventArgs(Control.MouseButtons, 0, p.X, p.Y, 0)); } } else if (m.Msg == (int)WinApi.WindowsMessages.WM_CAPTURECHANGED) { // Recapture the mouse... if (m.LParam == IntPtr.Zero && Control.MouseButtons == MouseButtons.Left && m_ScrollBarCore.MouseOverPart == ScrollBarCore.eScrollPart.Track) { m_ParentScrollBar.Capture = true; } } if (m.Msg == (int)WinApi.WindowsMessages.WM_PAINT) { if (m_FirstPaint) { // Call to base actually updates values returned by GetScrollBarInfo CallBaseWndProc(ref m); // Repaint the control once that is done SendDelayPaintMessage(); m_FirstPaint = false; } WinApi.PAINTSTRUCT ps = new WinApi.PAINTSTRUCT(); IntPtr hdc = WinApi.BeginPaint(m.HWnd, ref ps); try { Graphics g = Graphics.FromHdc(hdc); try { PaintInternal(g, hdc); } finally { g.Dispose(); } } finally { WinApi.EndPaint(m.HWnd, ref ps); } return false; } return true; } private void CallBaseWndProc(ref Message m) { m_ParentScrollBarWndProc.CallBaseWndProc(ref m); } private void SendDelayPaintMessage() { m_PaintTimer.Start(); } void PaintTimerTick(object sender, EventArgs e) { m_PaintTimer.Stop(); PaintUsingDC(); } private void InternalMouseDoubleClick(MouseEventArgs me) { PerformThumbClick(me.X, me.Y); } private void PerformThumbClick(int mouseX, int mouseY) { if (m_ScrollBarCore.MouseOverPart == ScrollBarCore.eScrollPart.ThumbDecrease) this.SetValue(Math.Max(m_ParentScrollBar.Value - m_ParentScrollBar.SmallChange, m_ParentScrollBar.Minimum), ScrollEventType.SmallDecrement); else if (m_ScrollBarCore.MouseOverPart == ScrollBarCore.eScrollPart.ThumbIncrease) this.SetValue(Math.Min(m_ParentScrollBar.Value + m_ParentScrollBar.SmallChange, m_ParentScrollBar.Maximum), ScrollEventType.SmallIncrement); else if (m_ScrollBarCore.MouseOverPart == ScrollBarCore.eScrollPart.Control) { if (this.IsVScroll) { if (mouseY < m_ScrollBarCore.TrackRectangle.Y) this.SetValue(Math.Max(m_ParentScrollBar.Value - m_ParentScrollBar.LargeChange, m_ParentScrollBar.Minimum), ScrollEventType.LargeDecrement); else if (mouseY > m_ScrollBarCore.TrackRectangle.Bottom) this.SetValue(Math.Min(m_ParentScrollBar.Value + m_ParentScrollBar.LargeChange, m_ParentScrollBar.Maximum), ScrollEventType.LargeIncrement); } else { if (mouseX < m_ScrollBarCore.TrackRectangle.X) this.SetValue(Math.Max(m_ParentScrollBar.Value - m_ParentScrollBar.LargeChange, m_ParentScrollBar.Minimum), ScrollEventType.LargeDecrement); else if (mouseX > m_ScrollBarCore.TrackRectangle.Right) this.SetValue(Math.Min(m_ParentScrollBar.Value + m_ParentScrollBar.LargeChange, m_ParentScrollBar.Maximum), ScrollEventType.LargeIncrement); } } } private void SetValue(int newValue, ScrollEventType type) { //FieldInfo fi = typeof(System.Windows.Forms.ScrollBar).GetField("value", BindingFlags.NonPublic | BindingFlags.Instance); //if (fi != null) //{ // fi.SetValue(this, newValue); // UpdateSystemScrollInfo(); //} //else if (m_ParentScrollBar.Value == newValue) return; if (m_UseLockWindowUpdate && m_ParentScrollBar.Parent != null) NativeFunctions.LockWindowUpdate(m_ParentScrollBar.Parent.Handle); else NativeFunctions.SendMessage(m_ParentScrollBar.Handle, NativeFunctions.WM_SETREDRAW, 0, 0); m_ParentScrollBarWndProc.SetValue(newValue, type); if (m_UseLockWindowUpdate && m_ParentScrollBar.Parent != null) NativeFunctions.LockWindowUpdate(IntPtr.Zero); else NativeFunctions.SendMessage(m_ParentScrollBar.Handle, NativeFunctions.WM_SETREDRAW, 1, 0); if (m_ParentScrollBar.Parent is DataGridView && type == ScrollEventType.ThumbTrack) { if (m_UseLockWindowUpdate) m_ParentScrollBar.Parent.Refresh(); else { Point p = m_ParentScrollBar.PointToClient(Control.MousePosition); if (!m_ParentScrollBar.ClientRectangle.Contains(p)) m_ParentScrollBar.Parent.Refresh(); } } PaintUsingDC(); } //private void UpdateSystemScrollInfo() //{ // if (this.IsHandleCreated && this.Enabled) // { // WinApi.SCROLLINFO si = new WinApi.SCROLLINFO(); // si.cbSize = Marshal.SizeOf(typeof(WinApi.SCROLLINFO)); // si.fMask = 0x17; // si.nMin = this.Minimum; // si.nMax = this.Maximum; // si.nPage = this.LargeChange; // if (this.RightToLeft == RightToLeft.Yes) // { // MethodInfo mi = typeof(System.Windows.Forms.ScrollBar).GetMethod("ReflectPosition", BindingFlags.NonPublic | BindingFlags.Instance); // if(mi!=null) // si.nPos = (int)mi.Invoke(this, new object[]{this.Value}); // //= this.ReflectPosition(this.value); // } // else // { // si.nPos = this.Value; // } // si.nTrackPos = 0; // WinApi.SetScrollInfo(new HandleRef(this, this.Handle), 2, ref si, false); // } //} private void InternalMouseUp(MouseEventArgs mouseEventArgs) { StopAutoScrollTimer(); m_ScrollBarCore.MouseUp(mouseEventArgs); m_ParentScrollBar.Invalidate(); m_MouseDownTrackOffset = 0; if (m_ParentScrollBar.Capture) m_ParentScrollBar.Capture = false; } private void InternalMouseDown(MouseEventArgs me) { m_MouseDownTrackOffset = 0; m_ScrollBarCore.MouseDown(me); if (m_ScrollBarCore.MouseOverPart != ScrollBarCore.eScrollPart.Track && m_ScrollBarCore.MouseOverPart != ScrollBarCore.eScrollPart.None) { PerformThumbClick(me.X, me.Y); StartAutoScrollTimer(); } else if (m_ScrollBarCore.MouseOverPart == ScrollBarCore.eScrollPart.Track) { if (IsVScroll) m_MouseDownTrackOffset = me.Y - m_ScrollBarCore.TrackRectangle.Y; else m_MouseDownTrackOffset = me.X - m_ScrollBarCore.TrackRectangle.X; } PaintUsingDC(); } private Timer m_Timer = null; private void StartAutoScrollTimer() { if (m_Timer == null) { m_Timer = new Timer(); m_Timer.Interval = 150; m_Timer.Tick += new EventHandler(TimerScrollTick); } m_Timer.Start(); } private void TimerScrollTick(object sender, EventArgs e) { Point p = m_ParentScrollBar.PointToClient(Control.MousePosition); PerformThumbClick(p.X, p.Y); } private void StopAutoScrollTimer() { if (m_Timer != null) { m_Timer.Stop(); m_Timer.Dispose(); m_Timer = null; } } private MouseButtons GetMouseButton(int wParam) { MouseButtons mb = MouseButtons.None; if ((wParam & (int)WinApi.MouseKeyState.MK_LBUTTON) != 0) mb |= MouseButtons.Left; if ((wParam & (int)WinApi.MouseKeyState.MK_MBUTTON) != 0) mb |= MouseButtons.Middle; if ((wParam & (int)WinApi.MouseKeyState.MK_RBUTTON) != 0) mb |= MouseButtons.Right; if ((wParam & (int)WinApi.MouseKeyState.MK_XBUTTON1) != 0) mb |= MouseButtons.XButton1; if ((wParam & (int)WinApi.MouseKeyState.MK_XBUTTON2) != 0) mb |= MouseButtons.XButton2; return mb; } private void PaintUsingDC() { IntPtr hdc = WinApi.GetWindowDC(m_ParentScrollBar.Handle); try { Graphics g = Graphics.FromHdc(hdc); try { PaintInternal(g, hdc); } finally { g.Dispose(); } } finally { WinApi.ReleaseDC(m_ParentScrollBar.Handle, hdc); } } private void PaintInternal(Graphics g, IntPtr hdc) { UpdateScrollValues(); using (BufferedBitmap bmp = new BufferedBitmap(g, new Rectangle(0, 0, m_ParentScrollBar.Width, m_ParentScrollBar.Height))) { m_ScrollBarCore.Paint(GetItemPaintArgs(bmp.Graphics)); bmp.Render(g); } } private ItemPaintArgs GetItemPaintArgs(Graphics g) { ItemPaintArgs pa = new ItemPaintArgs(m_ParentScrollBar as IOwner, m_ParentScrollBar, g, GetColorScheme()); pa.Renderer = this.GetRenderer(); pa.DesignerSelection = false; pa.GlassEnabled = false; return pa; } private ColorScheme m_ColorScheme = null; /// /// Returns the color scheme used by control. Color scheme for Office2007 style will be retrived from the current renderer instead of /// local color scheme referenced by ColorScheme property. /// /// An instance of ColorScheme object. protected virtual ColorScheme GetColorScheme() { BaseRenderer r = GetRenderer(); if (r is Office2007Renderer) return ((Office2007Renderer)r).ColorTable.LegacyColors; if (m_ColorScheme == null) m_ColorScheme = new ColorScheme(eDotNetBarStyle.Office2007); return m_ColorScheme; } private Rendering.BaseRenderer m_DefaultRenderer = null; private Rendering.BaseRenderer m_Renderer = null; private eRenderMode m_RenderMode = eRenderMode.Global; /// /// Returns the renderer control will be rendered with. /// /// The current renderer. public virtual Rendering.BaseRenderer GetRenderer() { if (m_RenderMode == eRenderMode.Global && Rendering.GlobalManager.Renderer != null) return Rendering.GlobalManager.Renderer; else if (m_RenderMode == eRenderMode.Custom && m_Renderer != null) return m_Renderer; if (m_DefaultRenderer == null) m_DefaultRenderer = new Rendering.Office2007Renderer(); return m_DefaultRenderer; } /// /// Gets or sets the redering mode used by control. Default value is eRenderMode.Global which means that static GlobalManager.Renderer is used. If set to Custom then Renderer property must /// also be set to the custom renderer that will be used. /// public eRenderMode RenderMode { get { return m_RenderMode; } set { if (m_RenderMode != value) { m_RenderMode = value; m_ParentScrollBar.Invalidate(true); } } } /// /// Gets or sets the custom renderer used by the items on this control. RenderMode property must also be set to eRenderMode.Custom in order renderer /// specified here to be used. /// public DevComponents.DotNetBar.Rendering.BaseRenderer Renderer { get { return m_Renderer; } set { m_Renderer = value; } } internal void OnMouseEnter(EventArgs e) { if (m_ParentScrollBar.Capture) m_ParentScrollBar.Capture = false; } internal void OnMouseLeave(EventArgs e) { StopAutoScrollTimer(); if (m_ScrollBarCore.MouseOverPart != ScrollBarCore.eScrollPart.None && Control.MouseButtons == MouseButtons.Left) m_ParentScrollBar.Capture = true; if (m_ScrollBarCore.IsMouseDown && Control.MouseButtons == MouseButtons.None) { m_ScrollBarCore.MouseUp(new MouseEventArgs(MouseButtons.Left, 0, -10, -10, 0)); SendDelayPaintMessage(); } else m_ScrollBarCore.MouseLeave(); } internal void OnMouseMove(MouseEventArgs e) { m_ScrollBarCore.MouseMove(e); if (m_ScrollBarCore.MouseOverPart == ScrollBarCore.eScrollPart.Track && e.Button == MouseButtons.Left) { Point p = m_ParentScrollBar.PointToClient(Control.MousePosition); SetValue(ValueFromMouseCoordinates(p), ScrollEventType.ThumbTrack); } } private int ValueFromMouseCoordinates(Point p) { if (IsVScroll) { int trackY = p.Y - m_MouseDownTrackOffset; trackY = Math.Max(trackY, m_ScrollBarCore.ThumbDecreaseRectangle.Bottom); trackY = Math.Min(trackY, m_ScrollBarCore.ThumbIncreaseRectangle.Y - GetTrackSize()); trackY -= m_ScrollBarCore.ThumbDecreaseRectangle.Bottom; int totalSize = GetAvailableTrackArea() - GetTrackSize(); return (int)((m_ParentScrollBar.Maximum - m_ParentScrollBar.Minimum) * ((float)trackY / (float)totalSize)); } else { int trackX = p.X - m_MouseDownTrackOffset; trackX = Math.Max(trackX, m_ScrollBarCore.ThumbDecreaseRectangle.Right); trackX = Math.Min(trackX, m_ScrollBarCore.ThumbIncreaseRectangle.X - GetTrackSize()); trackX -= m_ScrollBarCore.ThumbDecreaseRectangle.Right; int totalSize = GetAvailableTrackArea() - GetTrackSize(); return (int)((m_ParentScrollBar.Maximum - m_ParentScrollBar.Minimum) * ((float)trackX / (float)totalSize)); } } private int GetTrackSize() { if (IsVScroll) return m_ScrollBarCore.TrackRectangle.Height; else return m_ScrollBarCore.TrackRectangle.Width; } private int GetAvailableTrackArea() { if (IsVScroll) return m_ScrollBarCore.DisplayRectangle.Height - m_ScrollBarCore.ThumbDecreaseRectangle.Height - m_ScrollBarCore.ThumbIncreaseRectangle.Height; else return m_ScrollBarCore.DisplayRectangle.Width - m_ScrollBarCore.ThumbDecreaseRectangle.Width - m_ScrollBarCore.ThumbIncreaseRectangle.Width; } private bool IsVScroll { get { return m_IsVScrollBar; } } private void UpdateScrollValues() { WinApi.SCROLLBARINFO psbi = new WinApi.SCROLLBARINFO(); psbi.cbSize = Marshal.SizeOf(psbi); WinApi.GetScrollBarInfo(m_ParentScrollBar.Handle, (uint)WinApi.eObjectId.OBJID_CLIENT, ref psbi); Rectangle displayRect = new Rectangle(0, 0, m_ParentScrollBar.Width, m_ParentScrollBar.Height); if (IsVScroll) { if (m_ScrollBarCore.DisplayRectangle != displayRect) m_ScrollBarCore.DisplayRectangle = displayRect; Rectangle thumbRect = new Rectangle(displayRect.X, displayRect.Y, displayRect.Width, psbi.dxyLineButton); if (m_ScrollBarCore.ThumbDecreaseRectangle != thumbRect) m_ScrollBarCore.ThumbDecreaseRectangle = thumbRect; thumbRect = new Rectangle(displayRect.X, displayRect.Bottom - psbi.dxyLineButton, displayRect.Width, psbi.dxyLineButton); if (m_ScrollBarCore.ThumbIncreaseRectangle != thumbRect) m_ScrollBarCore.ThumbIncreaseRectangle = thumbRect; thumbRect = new Rectangle(displayRect.X, displayRect.Y + psbi.xyThumbTop, displayRect.Width, psbi.xyThumbBottom - psbi.xyThumbTop); if (m_ScrollBarCore.TrackRectangle != thumbRect) m_ScrollBarCore.TrackRectangle = thumbRect; } else { if (m_ScrollBarCore.DisplayRectangle != displayRect) m_ScrollBarCore.DisplayRectangle = displayRect; Rectangle thumbRect = new Rectangle(displayRect.X, displayRect.Y, psbi.dxyLineButton, displayRect.Height); if (m_ScrollBarCore.ThumbDecreaseRectangle != thumbRect) m_ScrollBarCore.ThumbDecreaseRectangle = thumbRect; thumbRect = new Rectangle(displayRect.Right - psbi.dxyLineButton, displayRect.Y, psbi.dxyLineButton, displayRect.Height); if (m_ScrollBarCore.ThumbIncreaseRectangle != thumbRect) m_ScrollBarCore.ThumbIncreaseRectangle = thumbRect; thumbRect = new Rectangle(displayRect.X + psbi.xyThumbTop, displayRect.Y, psbi.xyThumbBottom - psbi.xyThumbTop, displayRect.Height); if (m_ScrollBarCore.TrackRectangle != thumbRect) m_ScrollBarCore.TrackRectangle = thumbRect; } if (m_ScrollBarCore.Minimum != m_ParentScrollBar.Minimum) m_ScrollBarCore.Minimum = m_ParentScrollBar.Minimum; if (m_ScrollBarCore.Maximum != m_ParentScrollBar.Maximum) m_ScrollBarCore.Maximum = m_ParentScrollBar.Maximum; if (m_ScrollBarCore.SmallChange != m_ParentScrollBar.SmallChange) m_ScrollBarCore.SmallChange = m_ParentScrollBar.SmallChange; if (m_ScrollBarCore.LargeChange != m_ParentScrollBar.LargeChange) m_ScrollBarCore.LargeChange = m_ParentScrollBar.LargeChange; if (m_ScrollBarCore.Value != m_ParentScrollBar.Value) m_ScrollBarCore.Value = m_ParentScrollBar.Value; } internal void NotifyInvalidate(Rectangle invalidatedArea) { } //public bool IsAppScrollBarStyle //{ // get { return m_ScrollBarCore.IsAppScrollBarStyle; } // set // { // m_ScrollBarCore.IsAppScrollBarStyle = value; // m_ParentScrollBar.Invalidate(); // } //} #endregion #region IDisposable Members public void Dispose() { if (m_ScrollBarCore != null) { m_ScrollBarCore.Dispose(); m_ScrollBarCore = null; } if (m_PaintTimer != null) { m_PaintTimer.Stop(); m_PaintTimer.Dispose(); m_PaintTimer = null; } StopAutoScrollTimer(); } #endregion internal interface IScrollBarExtender { void CallBaseWndProc(ref Message m); void SetValue(int newValue, ScrollEventType type); } } }