-
-
Save ahmedosama007/c1b0cd327d395a5698c1e17e96d0f8f9 to your computer and use it in GitHub Desktop.
'Copyright (c) Smart PC Utilities, Ltd. | |
'All rights reserved. | |
#Region "References" | |
Imports System.ComponentModel | |
Imports System.Drawing.Imaging | |
Imports System.Drawing.Drawing2D | |
#End Region | |
Namespace Controls | |
<Designer(GetType(FlatScrollBarDesigner))> <ToolboxBitmap(GetType(ScrollBar))> <DefaultEvent("Scroll")> <DefaultProperty("Value")> Public Class FlatScrollBar | |
Inherits Control | |
Implements ITheme | |
#Region "Private Members" | |
Private _isDrawing As Boolean 'Indicates many changes to the scrollbar are happening, so stop painting till finished. | |
Private _barOrientation As ScrollBarOrientation = ScrollBarOrientation.Vertical 'The scrollbar orientation - horizontal / vertical. | |
Private _scrollOrientation As ScrollOrientation = ScrollOrientation.VerticalScroll 'The scroll orientation in scroll events. | |
Private _rectClickBar As Rectangle 'The clicked channel rectangle. | |
Private _rectThumb As Rectangle | |
Private _rectTopArrow As Rectangle | |
Private _rectBottomArrow As Rectangle | |
Private _rectChannel As Rectangle | |
Private _isTopArrowClicked As Boolean 'Indicates if top arrow was clicked. | |
Private _isBottomArrowClicked As Boolean 'Indicates if down arrow was clicked. | |
Private _isTopBarClicked As Boolean 'Indicates if channel rectangle above the thumb was clicked. | |
Private _isBottomBarClicked As Boolean 'Indicates if channel rectangle under the thumb was clicked. | |
Private _isThumbClicked As Boolean 'Indicates if the thumb was clicked. | |
Private _thumbState As ScrollBarState = ScrollBarState.Normal 'The state of the thumb. | |
Private _topArrowButtonState As ScrollBarArrowButtonState = ScrollBarArrowButtonState.UpNormal 'The state of the top arrow. | |
Private _bottomArrowButtonState As ScrollBarArrowButtonState = ScrollBarArrowButtonState.DownNormal 'The state of the bottom arrow. | |
Private _minimum As Integer | |
Private _maximum As Integer = 100 | |
Private _smallChange As Integer = 1 | |
Private _largeChange As Integer = 10 | |
Private _value As Integer | |
Private _thumbWidth As Integer = 10 | |
Private _thumbHeight As Integer | |
Private _arrowWidth As Integer = 18 | |
Private _arrowHeight As Integer = 18 | |
Private _thumbBottomLimitBottom As Integer 'The bottom limit for the thumb bottom. | |
Private _thumbBottomLimitTop As Integer 'The bottom limit for the thumb top. | |
Private _thumbTopLimit As Integer 'The top limit for the thumb top. | |
Private _thumbPosition As Integer 'The current position of the thumb. | |
Private _trackPosition As Integer 'The track position. | |
Private ReadOnly scrollTimer As New Timer() 'The progress timer for moving the thumb. | |
Private _theme As UITheme = UITheme.VS2019LightBlue | |
Private _backColor As Color = Color.FromArgb(242, 242, 242) | |
Private _borderColor As Color = Color.FromArgb(242, 242, 242) | |
Private _borderColorDisabled As Color = Color.FromArgb(242, 242, 242) | |
Private ReadOnly _thumbColors As Color() = New Color(3) {} | |
Private ReadOnly _arrowColors As Color() = New Color(3) {} | |
#End Region | |
#Region "Constants" | |
Private Const SETREDRAW As Integer = 11 ' Redraw constant | |
Private Const MINIMUM_SIZE As Integer = 10 | |
#End Region | |
#Region "Constructor" | |
Public Sub New() | |
SetStyle(ControlStyles.OptimizedDoubleBuffer Or ControlStyles.ResizeRedraw Or ControlStyles.AllPaintingInWmPaint Or ControlStyles.UserPaint, True) | |
SetStyle(ControlStyles.Selectable, False) | |
SetUpScrollBar() 'Setup the ScrollBar | |
AddHandler scrollTimer.Tick, AddressOf ScrollTimer_Tick | |
_thumbColors(0) = Color.FromArgb(194, 195, 201) 'Normal state | |
_thumbColors(1) = Color.FromArgb(104, 104, 104) 'Hover state | |
_thumbColors(2) = Color.FromArgb(91, 91, 91) 'Pressed state | |
_arrowColors(0) = Color.FromArgb(134, 137, 153) 'Normal state | |
_arrowColors(1) = Color.FromArgb(70, 181, 255) 'Hover state | |
_arrowColors(2) = Color.FromArgb(0, 122, 204) 'Pressed state | |
End Sub | |
#End Region | |
#Region "Events" | |
''' <summary> | |
''' Raised when the ScrollBar control is scrolled. | |
''' </summary> | |
<Category("Behavior")> <Description("Raised when the ScrollBar control is scrolled.")> Public Event Scroll As ScrollEventHandler | |
#End Region | |
#Region "Public Properties" | |
<Category("Layout")> <Description("Gets or sets the ScrollBar orientation.")> <DefaultValue(ScrollBarOrientation.Vertical)> Public Property Orientation As ScrollBarOrientation | |
Get | |
Return _barOrientation | |
End Get | |
Set | |
If Value <> _barOrientation Then | |
_barOrientation = Value | |
_scrollOrientation = If(Value = ScrollBarOrientation.Vertical, ScrollOrientation.VerticalScroll, ScrollOrientation.HorizontalScroll) | |
If DesignMode Then 'only in DesignMode switch width and height | |
Size = New Size(Height, Width) | |
End If | |
SetUpScrollBar() | |
End If | |
End Set | |
End Property | |
<Category("Behavior")> <Description("Gets or sets the ScrollBar minimum value.")> <DefaultValue(0)> Public Property Minimum As Integer | |
Get | |
Return _minimum | |
End Get | |
Set | |
If _minimum = Value OrElse Value < 0 OrElse Value >= _maximum Then | |
Return | |
End If | |
_minimum = Value | |
'Current large change value invalid - adjust | |
If _largeChange > _maximum - _minimum Then | |
_largeChange = _maximum - _minimum | |
End If | |
SetUpScrollBar() | |
If _value < Value Then 'Current value less than new minimum value - adjust | |
Me.Value = Value | |
Else | |
ChangeThumbPosition(GetThumbPosition()) 'Current value is valid - adjust thumb position | |
Refresh() | |
End If | |
End Set | |
End Property | |
<Category("Behavior")> <Description("Gets or sets the ScrollBar maximum value.")> <DefaultValue(100)> Public Property Maximum As Integer | |
Get | |
Return _maximum | |
End Get | |
Set | |
If Value = _maximum OrElse Value < 1 OrElse Value <= _minimum Then | |
Return | |
End If | |
_maximum = Value | |
If _largeChange > _maximum - _minimum Then | |
_largeChange = _maximum - _minimum | |
End If | |
SetUpScrollBar() | |
If _value > _maximum Then | |
Me.Value = _maximum | |
Else | |
ChangeThumbPosition(GetThumbPosition()) | |
Refresh() | |
End If | |
End Set | |
End Property | |
<Category("Behavior")> <Description("Gets or sets the ScrollBar small change value.")> <DefaultValue(1)> Public Property SmallChange As Integer | |
Get | |
Return _smallChange | |
End Get | |
Set | |
If Value = _smallChange OrElse Value < 1 OrElse Value >= _largeChange Then | |
Return | |
End If | |
_smallChange = Value | |
SetUpScrollBar() | |
End Set | |
End Property | |
<Category("Behavior")> <Description("Gets or sets the ScrollBar large change value.")> <DefaultValue(10)> Public Property LargeChange As Integer | |
Get | |
Return _largeChange | |
End Get | |
Set | |
If Value = _largeChange OrElse Value < _smallChange OrElse Value < 2 Then | |
Return | |
End If | |
_largeChange = If(Value > _maximum - _minimum, _maximum - _minimum, Value) | |
SetUpScrollBar() | |
End Set | |
End Property | |
<Category("Behavior")> <Description("Gets or sets the ScrollBar current value.")> <DefaultValue(0)> Public Property Value As Integer | |
Get | |
Return _value | |
End Get | |
Set | |
If _value = Value OrElse Value < _minimum OrElse Value > _maximum Then | |
Return | |
End If | |
_value = Value | |
ChangeThumbPosition(GetThumbPosition()) | |
OnScroll(New ScrollEventArgs(ScrollEventType.ThumbPosition, -1, _value, _scrollOrientation)) | |
Refresh() | |
End Set | |
End Property | |
<Category("Appearance")> <Description("The theme to apply to the Flat ScrollBar control.")> <DefaultValue(GetType(UITheme), "1")> Public Property Theme As UITheme Implements ITheme.Theme | |
Get | |
Return _theme | |
End Get | |
Set | |
_theme = Value | |
If _theme = UITheme.VS2019DarkBlue Then | |
_backColor = Color.FromArgb(62, 62, 66) | |
_borderColor = Color.FromArgb(62, 62, 66) | |
_borderColorDisabled = Color.FromArgb(62, 62, 66) | |
_thumbColors(0) = Color.FromArgb(104, 104, 104) | |
_thumbColors(1) = Color.FromArgb(158, 158, 158) | |
_thumbColors(2) = Color.FromArgb(239, 235, 239) | |
_arrowColors(0) = Color.FromArgb(153, 153, 153) | |
_arrowColors(1) = Color.FromArgb(28, 151, 234) | |
_arrowColors(2) = Color.FromArgb(0, 122, 204) | |
ElseIf _theme = UITheme.VS2019LightBlue Then | |
_backColor = Color.FromArgb(245, 245, 245) | |
_borderColor = Color.FromArgb(245, 245, 245) | |
_borderColorDisabled = Color.FromArgb(245, 245, 245) | |
_thumbColors(0) = Color.FromArgb(194, 195, 201) 'Normal state | |
_thumbColors(1) = Color.FromArgb(104, 104, 104) 'Hover state | |
_thumbColors(2) = Color.FromArgb(91, 91, 91) 'Pressed state | |
_arrowColors(0) = Color.FromArgb(134, 137, 153) 'Normal state | |
_arrowColors(1) = Color.FromArgb(28, 151, 234) 'Hover state | |
_arrowColors(2) = Color.FromArgb(0, 122, 204) 'Pressed state | |
ElseIf _theme = UITheme.Custom Then | |
ParentTheme = False | |
End If | |
Invalidate() | |
End Set | |
End Property | |
<Category("Appearance")> <Description("True to allow the control to inherit the parent control style.")> <DefaultValue(True)> Public Property ParentTheme As Boolean = True Implements ITheme.ParentTheme | |
#End Region | |
#Region "Public Methods" | |
Public Sub BeginUpdate() | |
NativeMethods.SendMessage(Handle, SETREDRAW, False, 0) | |
_isDrawing = True | |
End Sub | |
Public Sub EndUpdate() | |
NativeMethods.SendMessage(Handle, SETREDRAW, True, 0) | |
_isDrawing = False | |
SetUpScrollBar() | |
Refresh() | |
End Sub | |
#End Region | |
#Region "Overridden Methods" | |
Protected Overridable Sub OnScroll(e As ScrollEventArgs) | |
RaiseEvent Scroll(Me, e) | |
End Sub | |
Protected Overrides Sub OnPaint(e As PaintEventArgs) | |
If e Is Nothing Then Return | |
Dim g = e.Graphics | |
g.SmoothingMode = SmoothingMode.AntiAlias | |
DrawBackground(g, ClientRectangle) | |
DrawThumb(g, _rectThumb, _thumbState) | |
DrawArrowButton(g, _rectTopArrow, _topArrowButtonState, True, _barOrientation) | |
DrawArrowButton(g, _rectBottomArrow, _bottomArrowButtonState, False, _barOrientation) | |
If _isTopBarClicked Then | |
If _barOrientation = ScrollBarOrientation.Vertical Then | |
_rectClickBar.Y = _thumbTopLimit | |
_rectClickBar.Height = _rectThumb.Y - _thumbTopLimit | |
Else | |
_rectClickBar.X = _thumbTopLimit | |
_rectClickBar.Width = _rectThumb.X - _thumbTopLimit | |
End If | |
ElseIf _isBottomBarClicked Then | |
If _barOrientation = ScrollBarOrientation.Vertical Then | |
_rectClickBar.Y = _rectThumb.Bottom + 1 | |
_rectClickBar.Height = _thumbBottomLimitBottom - _rectClickBar.Y + 1 | |
Else | |
_rectClickBar.X = _rectThumb.Right + 1 | |
_rectClickBar.Width = _thumbBottomLimitBottom - _rectClickBar.X + 1 | |
End If | |
End If | |
'Draw border | |
Using p As New Pen(If(Enabled, _borderColor, _borderColorDisabled)) | |
e.Graphics.DrawRectangle(p, 0, 0, Width - 1, Height - 1) | |
End Using | |
End Sub | |
Protected Overrides Sub OnMouseDown(e As MouseEventArgs) | |
MyBase.OnMouseDown(e) | |
Focus() | |
If e.Button = MouseButtons.Left Then | |
Dim mouseLocation As Point = e.Location | |
If _rectThumb.Contains(mouseLocation) Then | |
_isThumbClicked = True | |
_thumbPosition = If(_barOrientation = ScrollBarOrientation.Vertical, mouseLocation.Y - _rectThumb.Y, mouseLocation.X - _rectThumb.X) | |
_thumbState = ScrollBarState.Pressed | |
Invalidate(_rectThumb) | |
ElseIf _rectTopArrow.Contains(mouseLocation) Then | |
_isTopArrowClicked = True | |
_topArrowButtonState = ScrollBarArrowButtonState.UpPressed | |
Invalidate(_rectTopArrow) | |
ProgressThumb(True) | |
ElseIf _rectBottomArrow.Contains(mouseLocation) Then | |
_isBottomArrowClicked = True | |
_bottomArrowButtonState = ScrollBarArrowButtonState.DownPressed | |
Invalidate(_rectBottomArrow) | |
ProgressThumb(True) | |
Else | |
_trackPosition = If(_barOrientation = ScrollBarOrientation.Vertical, mouseLocation.Y, mouseLocation.X) | |
If _trackPosition < If(_barOrientation = ScrollBarOrientation.Vertical, _rectThumb.Y, _rectThumb.X) Then | |
_isTopBarClicked = True | |
Else | |
_isBottomBarClicked = True | |
End If | |
ProgressThumb(True) | |
End If | |
ElseIf e.Button = MouseButtons.Right Then | |
_trackPosition = If(_barOrientation = ScrollBarOrientation.Vertical, e.Y, e.X) | |
End If | |
End Sub | |
Protected Overrides Sub OnMouseUp(e As MouseEventArgs) | |
MyBase.OnMouseUp(e) | |
If e.Button = MouseButtons.Left Then | |
If _isThumbClicked Then | |
_isThumbClicked = False | |
_thumbState = ScrollBarState.Normal | |
OnScroll(New ScrollEventArgs(ScrollEventType.EndScroll, -1, _value, _scrollOrientation)) | |
ElseIf _isTopArrowClicked Then | |
_isTopArrowClicked = False | |
_topArrowButtonState = ScrollBarArrowButtonState.UpNormal | |
scrollTimer.[Stop]() | |
ElseIf _isBottomArrowClicked Then | |
_isBottomArrowClicked = False | |
_bottomArrowButtonState = ScrollBarArrowButtonState.DownNormal | |
scrollTimer.[Stop]() | |
ElseIf _isTopBarClicked Then | |
_isTopBarClicked = False | |
scrollTimer.[Stop]() | |
ElseIf _isBottomBarClicked Then | |
_isBottomBarClicked = False | |
scrollTimer.[Stop]() | |
End If | |
Invalidate() | |
End If | |
End Sub | |
Protected Overrides Sub OnMouseLeave(e As EventArgs) | |
MyBase.OnMouseLeave(e) | |
RefreshScrollBar() | |
End Sub | |
Protected Overrides Sub OnMouseMove(e As MouseEventArgs) | |
MyBase.OnMouseMove(e) | |
If e.Button = MouseButtons.Left Then 'Moving and holding the left mouse button | |
If _isThumbClicked Then | |
Dim oldValue As Integer = _value | |
Dim pos As Integer = If(_barOrientation = ScrollBarOrientation.Vertical, e.Location.Y, e.Location.X) | |
If pos <= (_thumbTopLimit + _thumbPosition) Then 'The thumb is all the way to the top | |
ChangeThumbPosition(_thumbTopLimit) | |
_value = _minimum | |
ElseIf pos >= (_thumbBottomLimitTop + _thumbPosition) Then 'The thumb is all the way to the bottom | |
ChangeThumbPosition(_thumbBottomLimitTop) | |
_value = _maximum | |
Else 'The thumb is between the ends of the track. | |
ChangeThumbPosition(pos - _thumbPosition) | |
Dim pixelRange, thumbPos, arrowSize As Integer | |
'Calculate the value - first some helper variables dependent on the current orientation | |
If _barOrientation = ScrollBarOrientation.Vertical Then | |
pixelRange = Height - (2 * _arrowHeight) - _thumbHeight | |
thumbPos = _rectThumb.Y | |
arrowSize = _arrowHeight | |
Else | |
pixelRange = Width - (2 * _arrowWidth) - _thumbWidth | |
thumbPos = _rectThumb.X | |
arrowSize = _arrowWidth | |
End If | |
Dim perc As Single = 0F | |
If pixelRange <> 0 Then | |
perc = CSng(thumbPos - arrowSize) / CSng(pixelRange) | |
End If | |
_value = Convert.ToInt32((perc * (_maximum - _minimum)) + _minimum) | |
End If | |
If oldValue <> _value Then | |
OnScroll(New ScrollEventArgs(ScrollEventType.ThumbTrack, oldValue, _value, _scrollOrientation)) | |
Refresh() | |
End If | |
End If | |
ElseIf Not ClientRectangle.Contains(e.Location) Then | |
RefreshScrollBar() | |
ElseIf e.Button = MouseButtons.None Then 'Only moving the mouse | |
If _rectTopArrow.Contains(e.Location) Then | |
_topArrowButtonState = ScrollBarArrowButtonState.UpHot | |
Invalidate(_rectTopArrow) | |
ElseIf _rectBottomArrow.Contains(e.Location) Then | |
_bottomArrowButtonState = ScrollBarArrowButtonState.DownHot | |
Invalidate(_rectBottomArrow) | |
ElseIf _rectThumb.Contains(e.Location) Then | |
_thumbState = ScrollBarState.Hot | |
Invalidate(_rectThumb) | |
Else | |
_thumbState = ScrollBarState.Normal | |
_topArrowButtonState = ScrollBarArrowButtonState.UpNormal | |
_bottomArrowButtonState = ScrollBarArrowButtonState.DownNormal | |
Refresh() | |
End If | |
End If | |
End Sub | |
Protected Overrides Sub OnMouseWheel(e As MouseEventArgs) | |
MyBase.OnMouseWheel(e) | |
Dim oldValue = _value | |
Dim scrollType As ScrollEventType | |
If e.Delta >= 0 Then 'Decrease value | |
_value = GetScrollValue(False, True) | |
If _value = _minimum Then | |
scrollType = ScrollEventType.First | |
ChangeThumbPosition(_thumbTopLimit) | |
Else | |
scrollType = ScrollEventType.LargeDecrement | |
ChangeThumbPosition(Math.Max(_thumbTopLimit, GetThumbPosition())) | |
End If | |
Else 'Increase value | |
_value = GetScrollValue(False, False) | |
If _value = _maximum Then | |
scrollType = ScrollEventType.Last | |
ChangeThumbPosition(_thumbBottomLimitTop) | |
Else | |
scrollType = ScrollEventType.SmallIncrement | |
ChangeThumbPosition(Math.Min(_thumbBottomLimitTop, GetThumbPosition())) | |
End If | |
End If | |
If oldValue <> _value Then | |
OnScroll(New ScrollEventArgs(scrollType, oldValue, _value, _scrollOrientation)) | |
Invalidate(_rectChannel) | |
End If | |
End Sub | |
Protected Overrides Sub SetBoundsCore(x As Integer, y As Integer, width As Integer, height As Integer, specified As BoundsSpecified) | |
If DesignMode Then | |
If _barOrientation = ScrollBarOrientation.Vertical Then | |
Dim minHeight = (2 * _arrowHeight) + MINIMUM_SIZE | |
If height < minHeight Then height = minHeight | |
width = SystemInformation.VerticalScrollBarWidth | |
Else | |
Dim minWidth = (2 * _arrowWidth) + MINIMUM_SIZE | |
If width < minWidth Then width = minWidth | |
height = SystemInformation.VerticalScrollBarWidth | |
End If | |
End If | |
MyBase.SetBoundsCore(x, y, width, height, specified) | |
If DesignMode Then SetUpScrollBar() | |
End Sub | |
Protected Overrides Sub OnSizeChanged(e As EventArgs) | |
MyBase.OnSizeChanged(e) | |
SetUpScrollBar() | |
End Sub | |
Protected Overrides Function ProcessDialogKey(keyData As Keys) As Boolean | |
Dim isHandled As Boolean | |
Dim oldValue = _value | |
Dim scrollType As ScrollEventType | |
Dim keyUp As Keys = Keys.Up | |
Dim keyDown As Keys = Keys.Down | |
If _barOrientation = ScrollBarOrientation.Horizontal Then | |
keyUp = Keys.Left | |
keyDown = Keys.Right | |
End If | |
Select Case keyData | |
Case keyUp | |
_value = GetScrollValue(True, True) | |
If _value = _minimum Then | |
scrollType = ScrollEventType.First | |
ChangeThumbPosition(_thumbTopLimit) | |
Else | |
scrollType = ScrollEventType.SmallDecrement | |
ChangeThumbPosition(Math.Max(_thumbTopLimit, GetThumbPosition())) | |
End If | |
isHandled = True | |
Case keyDown | |
_value = GetScrollValue(True, False) | |
If _value = _maximum Then | |
scrollType = ScrollEventType.Last | |
ChangeThumbPosition(_thumbBottomLimitTop) | |
Else | |
scrollType = ScrollEventType.SmallIncrement | |
ChangeThumbPosition(Math.Min(_thumbBottomLimitTop, GetThumbPosition())) | |
End If | |
isHandled = True | |
Case Keys.PageUp | |
_value = GetScrollValue(False, True) | |
If _value = _minimum Then | |
scrollType = ScrollEventType.First | |
ChangeThumbPosition(_thumbTopLimit) | |
Else | |
scrollType = ScrollEventType.LargeDecrement | |
ChangeThumbPosition(Math.Max(_thumbTopLimit, GetThumbPosition())) | |
End If | |
isHandled = True | |
Case Keys.PageDown | |
_value = GetScrollValue(False, False) | |
If _value = _maximum Then | |
scrollType = ScrollEventType.Last | |
ChangeThumbPosition(_thumbBottomLimitTop) | |
Else | |
scrollType = ScrollEventType.SmallIncrement | |
ChangeThumbPosition(Math.Min(_thumbBottomLimitTop, GetThumbPosition())) | |
End If | |
isHandled = True | |
Case Keys.Home | |
_value = _minimum | |
scrollType = ScrollEventType.First | |
ChangeThumbPosition(_thumbTopLimit) | |
isHandled = True | |
Case Keys.End | |
_value = _maximum | |
scrollType = ScrollEventType.Last | |
ChangeThumbPosition(_thumbBottomLimitTop) | |
isHandled = True | |
End Select | |
If isHandled AndAlso oldValue <> _value Then | |
OnScroll(New ScrollEventArgs(scrollType, oldValue, _value, _scrollOrientation)) | |
Invalidate(_rectChannel) | |
End If | |
Return isHandled | |
Return MyBase.ProcessDialogKey(keyData) | |
End Function | |
Protected Overrides Sub OnEnabledChanged(e As EventArgs) | |
MyBase.OnEnabledChanged(e) | |
If Enabled Then | |
_thumbState = ScrollBarState.Normal | |
_topArrowButtonState = ScrollBarArrowButtonState.UpNormal | |
_bottomArrowButtonState = ScrollBarArrowButtonState.DownNormal | |
Else | |
_thumbState = ScrollBarState.Disabled | |
_topArrowButtonState = ScrollBarArrowButtonState.UpDisabled | |
_bottomArrowButtonState = ScrollBarArrowButtonState.DownDisabled | |
End If | |
Refresh() | |
End Sub | |
#End Region | |
#Region "Overriden Properties" | |
Protected Overrides ReadOnly Property DefaultSize As Size | |
Get | |
Return New Size(SystemInformation.VerticalScrollBarWidth, 200) | |
End Get | |
End Property | |
#End Region | |
#Region "Private Methods" | |
Private Sub SetUpScrollBar() | |
If _isDrawing Then Return | |
If _barOrientation = ScrollBarOrientation.Vertical Then | |
_arrowHeight = 18 | |
_arrowWidth = 18 | |
_thumbWidth = 9 | |
_thumbHeight = GetThumbSize() | |
_rectClickBar = ClientRectangle | |
_rectClickBar.Inflate(-1, -1) | |
_rectClickBar.Y += _arrowHeight | |
_rectClickBar.Height -= _arrowHeight * 2 | |
_rectChannel = _rectClickBar | |
_rectThumb = New Rectangle(CInt(ClientRectangle.Right / 2) - CInt(_thumbWidth / 2), ClientRectangle.Y + _arrowHeight, _thumbWidth, _thumbHeight) | |
_rectTopArrow = New Rectangle(CInt(ClientRectangle.Right / 2) - CInt(_arrowWidth / 2) + 1, ClientRectangle.Y + 1, _arrowWidth, _arrowHeight) | |
_rectBottomArrow = New Rectangle(CInt(ClientRectangle.Right / 2) - CInt(_arrowWidth / 2), ClientRectangle.Bottom - _arrowHeight - 1, _arrowWidth, _arrowHeight) | |
_thumbPosition = CInt(_rectThumb.Height / 2) | |
_thumbBottomLimitBottom = ClientRectangle.Bottom - _arrowHeight - 2 | |
_thumbBottomLimitTop = _thumbBottomLimitBottom - _rectThumb.Height | |
_thumbTopLimit = ClientRectangle.Y + _arrowHeight + 2 | |
Else | |
_arrowHeight = 18 | |
_arrowWidth = 18 | |
_thumbHeight = 9 | |
_thumbWidth = GetThumbSize() | |
_rectClickBar = ClientRectangle | |
_rectClickBar.Inflate(-1, -1) | |
_rectClickBar.X += _arrowWidth | |
_rectClickBar.Width -= _arrowWidth * 2 | |
_rectChannel = _rectClickBar | |
_rectThumb = New Rectangle(ClientRectangle.X + _arrowWidth, CInt(ClientRectangle.Bottom / 2) - CInt(_thumbHeight / 2), _thumbWidth, _thumbHeight) | |
_rectTopArrow = New Rectangle(ClientRectangle.X + 2, CInt(ClientRectangle.Bottom / 2) - CInt(_arrowHeight / 2), _arrowWidth, _arrowHeight) | |
_rectBottomArrow = New Rectangle(ClientRectangle.Right - _arrowWidth - 2, CInt(ClientRectangle.Bottom / 2) - CInt(_arrowHeight / 2) + 1, _arrowWidth, _arrowHeight) | |
_thumbPosition = CInt(_rectThumb.Width / 2) | |
_thumbBottomLimitBottom = ClientRectangle.Right - _arrowWidth - 3 | |
_thumbBottomLimitTop = _thumbBottomLimitBottom - _rectThumb.Width | |
_thumbTopLimit = ClientRectangle.X + _arrowWidth + 3 | |
End If | |
ChangeThumbPosition(GetThumbPosition()) | |
Refresh() | |
End Sub | |
Private Sub RefreshScrollBar() | |
Dim pt As Point = PointToClient(Cursor.Position) | |
If ClientRectangle.Contains(pt) Then | |
If _rectThumb.Contains(pt) Then | |
_thumbState = ScrollBarState.Hot | |
_topArrowButtonState = ScrollBarArrowButtonState.UpNormal | |
_bottomArrowButtonState = ScrollBarArrowButtonState.DownNormal | |
ElseIf _rectTopArrow.Contains(pt) Then | |
_thumbState = ScrollBarState.Normal | |
_topArrowButtonState = ScrollBarArrowButtonState.UpActive | |
_bottomArrowButtonState = ScrollBarArrowButtonState.DownNormal | |
ElseIf _rectBottomArrow.Contains(pt) Then | |
_thumbState = ScrollBarState.Normal | |
_topArrowButtonState = ScrollBarArrowButtonState.UpNormal | |
_bottomArrowButtonState = ScrollBarArrowButtonState.DownActive | |
Else | |
_thumbState = ScrollBarState.Normal | |
_topArrowButtonState = ScrollBarArrowButtonState.UpNormal | |
_bottomArrowButtonState = ScrollBarArrowButtonState.DownNormal | |
End If | |
Else | |
_thumbState = ScrollBarState.Normal | |
_topArrowButtonState = ScrollBarArrowButtonState.UpNormal | |
_bottomArrowButtonState = ScrollBarArrowButtonState.DownNormal | |
End If | |
_isTopArrowClicked = False | |
_isBottomArrowClicked = False | |
_isTopBarClicked = False | |
_isBottomBarClicked = False | |
scrollTimer.[Stop]() | |
Refresh() | |
End Sub | |
Private Function GetScrollValue(isSmallChange As Boolean, isDecreaseValue As Boolean) As Integer | |
Dim newValue As Integer | |
If isDecreaseValue Then | |
newValue = _value - If(isSmallChange, _smallChange, _largeChange) | |
If newValue < _minimum Then newValue = _minimum | |
Else | |
newValue = _value + If(isSmallChange, _smallChange, _largeChange) | |
If newValue > _maximum Then newValue = _maximum | |
End If | |
Return newValue | |
End Function | |
Private Function GetThumbPosition() As Integer | |
Dim pixelRange = If(_barOrientation = ScrollBarOrientation.Vertical, _rectChannel.Height, _rectChannel.Width) | |
Dim realRange As Integer = _maximum - _minimum | |
Dim perc As Single = 0F | |
If realRange <> 0 Then | |
perc = CSng((_value - _minimum) / realRange) | |
End If | |
Return Math.Max(_thumbTopLimit, Math.Min(_thumbBottomLimitTop, Convert.ToInt32(perc * pixelRange))) | |
End Function | |
Private Function GetThumbSize() As Integer | |
Dim trackSize As Integer = If(_barOrientation = ScrollBarOrientation.Vertical, Height, Width) | |
If _maximum = 0 OrElse _largeChange = 0 Then | |
Return trackSize | |
End If | |
Dim thumbSize As Single = CSng(_largeChange * trackSize / _maximum) | |
Return Convert.ToInt32(Math.Min(trackSize, Math.Max(thumbSize, 10.0F))) | |
End Function | |
Private Sub ChangeThumbPosition(position As Integer) | |
If _barOrientation = ScrollBarOrientation.Vertical Then | |
_rectThumb.Y = position | |
Else | |
_rectThumb.X = position | |
End If | |
Dim pt As Point = PointToClient(Cursor.Position) | |
If _rectThumb.Contains(pt) Then | |
_thumbState = ScrollBarState.Hot | |
Invalidate(_rectThumb) | |
End If | |
End Sub | |
Private Sub ProgressThumb(isContinousScroll As Boolean) | |
Dim oldValue = _value | |
Dim type As ScrollEventType = ScrollEventType.First | |
Dim thumbSize, thumbPos As Integer | |
If _barOrientation = ScrollBarOrientation.Vertical Then | |
thumbPos = _rectThumb.Y | |
thumbSize = _rectThumb.Height | |
Else | |
thumbPos = _rectThumb.X | |
thumbSize = _rectThumb.Width | |
End If | |
If _isBottomArrowClicked OrElse (_isBottomBarClicked AndAlso (thumbPos + thumbSize) < _trackPosition) Then | |
type = If(_isBottomArrowClicked, ScrollEventType.SmallIncrement, ScrollEventType.LargeIncrement) | |
_value = GetScrollValue(_isBottomArrowClicked, False) | |
If _value = _maximum Then | |
ChangeThumbPosition(_thumbBottomLimitTop) | |
type = ScrollEventType.Last | |
Else | |
ChangeThumbPosition(Math.Min(_thumbBottomLimitTop, GetThumbPosition())) | |
End If | |
ElseIf _isTopArrowClicked OrElse (_isTopBarClicked AndAlso thumbPos > _trackPosition) Then | |
type = If(_isTopArrowClicked, ScrollEventType.SmallDecrement, ScrollEventType.LargeDecrement) | |
_value = GetScrollValue(_isTopArrowClicked, True) | |
If _value = _minimum Then | |
ChangeThumbPosition(_thumbTopLimit) | |
type = ScrollEventType.First | |
Else | |
ChangeThumbPosition(Math.Max(_thumbTopLimit, GetThumbPosition())) | |
End If | |
ElseIf Not ((_isTopArrowClicked AndAlso thumbPos = _thumbTopLimit) OrElse (_isBottomArrowClicked AndAlso thumbPos = _thumbBottomLimitTop)) Then | |
RefreshScrollBar() | |
Return | |
End If | |
If oldValue <> _value Then | |
OnScroll(New ScrollEventArgs(type, oldValue, _value, _scrollOrientation)) | |
Invalidate(_rectChannel) | |
If isContinousScroll Then StartScrollTimer() | |
End If | |
End Sub | |
#End Region | |
#Region "Timer Methods" | |
Private Sub ScrollTimer_Tick(sender As Object, e As EventArgs) | |
ProgressThumb(True) | |
End Sub | |
Private Sub StartScrollTimer() | |
If Not scrollTimer.Enabled Then | |
scrollTimer.Interval = 50 'Initial delay | |
scrollTimer.Start() | |
Else | |
scrollTimer.Interval = 10 | |
End If | |
End Sub | |
#End Region | |
#Region "Drawing Methods" | |
Private Sub DrawBackground(g As Graphics, rect As Rectangle) | |
If g Is Nothing OrElse rect.IsEmpty OrElse g.IsVisibleClipEmpty OrElse Not g.VisibleClipBounds.IntersectsWith(rect) Then Return | |
Using sb = New SolidBrush(_backColor) | |
g.FillRectangle(sb, rect) | |
End Using | |
End Sub | |
Private Sub DrawThumb(g As Graphics, rect As Rectangle, state As ScrollBarState) | |
If g Is Nothing OrElse rect.IsEmpty OrElse g.IsVisibleClipEmpty OrElse Not g.VisibleClipBounds.IntersectsWith(rect) OrElse state = ScrollBarState.Disabled Then | |
Return | |
End If | |
Dim index = 0 | |
Select Case state | |
Case ScrollBarState.Hot | |
index = 1 | |
Case ScrollBarState.Pressed | |
index = 2 | |
End Select | |
Using sb As New SolidBrush(_thumbColors(index)) | |
g.FillRectangle(sb, rect) | |
End Using | |
End Sub | |
Private Sub DrawArrowButton(g As Graphics, rect As Rectangle, state As ScrollBarArrowButtonState, isUpArrow As Boolean, orient As ScrollBarOrientation) | |
If g Is Nothing OrElse rect.IsEmpty OrElse g.IsVisibleClipEmpty OrElse Not g.VisibleClipBounds.IntersectsWith(rect) Then | |
Return | |
End If | |
If orient = ScrollBarOrientation.Vertical Then | |
DrawVerticalArrowButton(g, rect, state, isUpArrow) | |
Else | |
DrawHorizontalArrowButton(g, rect, state, isUpArrow) | |
End If | |
End Sub | |
Private Sub DrawVerticalArrowButton(g As Graphics, rect As Rectangle, state As ScrollBarArrowButtonState, arrowUp As Boolean) | |
Using img As Image = GetDownArrowButtonImage(state) | |
If arrowUp Then img.RotateFlip(RotateFlipType.Rotate180FlipNone) | |
g.DrawImage(img, rect) | |
End Using | |
End Sub | |
Private Sub DrawHorizontalArrowButton(g As Graphics, rect As Rectangle, state As ScrollBarArrowButtonState, arrowUp As Boolean) | |
Using img As Image = GetDownArrowButtonImage(state) | |
If arrowUp Then | |
img.RotateFlip(RotateFlipType.Rotate90FlipNone) | |
Else | |
img.RotateFlip(RotateFlipType.Rotate270FlipNone) | |
End If | |
g.DrawImage(img, rect) | |
End Using | |
End Sub | |
Private Function GetDownArrowButtonImage(state As ScrollBarArrowButtonState) As Image | |
Dim rect As New Rectangle(0, 0, _arrowWidth, _arrowHeight) | |
Dim bitmap As New Bitmap(_arrowWidth, _arrowHeight, PixelFormat.Format32bppArgb) | |
Dim g As Graphics = Graphics.FromImage(bitmap) | |
g.SmoothingMode = SmoothingMode.None | |
g.InterpolationMode = InterpolationMode.HighQualityBicubic | |
Dim index = 0 | |
Select Case state | |
Case ScrollBarArrowButtonState.UpHot, ScrollBarArrowButtonState.DownHot | |
index = 1 | |
Case ScrollBarArrowButtonState.UpActive, ScrollBarArrowButtonState.DownActive | |
index = 1 | |
Case ScrollBarArrowButtonState.UpPressed, ScrollBarArrowButtonState.DownPressed | |
index = 2 | |
End Select | |
Using sb = New SolidBrush(_arrowColors(index)) | |
g.FillPolygon(sb, GetDownArrowPos(rect)) | |
End Using | |
g.Dispose() | |
Return bitmap | |
End Function | |
Private Shared Function GetDownArrowPos(r As Rectangle) As Point() | |
Dim middle = New Point(r.Left + CInt(r.Width / 2), r.Top + CInt(r.Height / 2)) | |
Return {New Point(middle.X - 4, middle.Y - 3), New Point(middle.X + 4, middle.Y - 2), New Point(middle.X, middle.Y + 2)} | |
End Function | |
#End Region | |
#Region "Enumerations" | |
Private Enum ScrollBarArrowButtonState | |
''' <summary> | |
''' Indicates the up arrow is in normal state. | |
''' </summary> | |
UpNormal | |
''' <summary> | |
''' Indicates the up arrow is in hot state. | |
''' </summary> | |
UpHot | |
''' <summary> | |
''' Indicates the up arrow is in active state. | |
''' </summary> | |
UpActive | |
''' <summary> | |
''' Indicates the up arrow is in pressed state. | |
''' </summary> | |
UpPressed | |
''' <summary> | |
''' Indicates the up arrow is in disabled state. | |
''' </summary> | |
UpDisabled | |
''' <summary> | |
''' Indicates the down arrow is in normal state. | |
''' </summary> | |
DownNormal | |
''' <summary> | |
''' Indicates the down arrow is in hot state. | |
''' </summary> | |
DownHot | |
''' <summary> | |
''' Indicates the down arrow is in active state. | |
''' </summary> | |
DownActive | |
''' <summary> | |
''' Indicates the down arrow is in pressed state. | |
''' </summary> | |
DownPressed | |
''' <summary> | |
''' Indicates the down arrow is in disabled state. | |
''' </summary> | |
DownDisabled | |
End Enum | |
Private Enum ScrollBarState | |
''' <summary> | |
''' Indicates a normal scrollbar state. | |
''' </summary> | |
Normal | |
''' <summary> | |
''' Indicates a hot scrollbar state. | |
''' </summary> | |
Hot | |
''' <summary> | |
''' Indicates an active scrollbar state. | |
''' </summary> | |
Active | |
''' <summary> | |
''' Indicates a pressed scrollbar state. | |
''' </summary> | |
Pressed | |
''' <summary> | |
''' Indicates a disabled scrollbar state. | |
''' </summary> | |
Disabled | |
End Enum | |
#End Region | |
End Class | |
End Namespace |
'Copyright (c) Smart PC Utilities, Ltd. | |
'All rights reserved. | |
#Region "References" | |
Imports System.ComponentModel | |
Imports System.Windows.Forms.Design | |
#End Region | |
Namespace Controls | |
Friend Class FlatScrollBarDesigner | |
Inherits ControlDesigner | |
#Region "Overridden Properties" | |
Public Overrides ReadOnly Property SelectionRules As SelectionRules | |
Get | |
Dim propDescriptor As PropertyDescriptor = TypeDescriptor.GetProperties(Component)("Orientation") | |
If propDescriptor IsNot Nothing Then | |
Dim orientation As ScrollBarOrientation = CType(propDescriptor.GetValue(Component), ScrollBarOrientation) | |
Return If(orientation = ScrollBarOrientation.Vertical, | |
SelectionRules.Visible Or SelectionRules.Moveable Or SelectionRules.BottomSizeable Or SelectionRules.TopSizeable, | |
SelectionRules.Visible Or SelectionRules.Moveable Or SelectionRules.LeftSizeable Or SelectionRules.RightSizeable) | |
End If | |
Return MyBase.SelectionRules | |
End Get | |
End Property | |
#End Region | |
#Region "Overridden Methods" | |
Protected Overrides Sub PreFilterProperties(properties As IDictionary) | |
properties.Remove("Text") | |
properties.Remove("BackgroundImage") | |
properties.Remove("ForeColor") | |
properties.Remove("ImeMode") | |
properties.Remove("Padding") | |
properties.Remove("BackgroundImageLayout") | |
properties.Remove("BackColor") | |
properties.Remove("Font") | |
properties.Remove("RightToLeft") | |
MyBase.PreFilterProperties(properties) | |
End Sub | |
#End Region | |
End Class | |
End Namespace |
'Copyright (c) Smart PC Utilities, Ltd. | |
'All rights reserved. | |
Public Interface ITheme | |
#Region "Properties" | |
''' <summary> | |
''' Get or set the control style | |
''' </summary> | |
Property Theme As UITheme | |
''' <summary> | |
''' Get or set whether to allow the control to inherit the parent control style | |
''' </summary> | |
Property ParentTheme As Boolean | |
#End Region | |
End Interface |
'Copyright (c) Smart PC Utilities, Ltd. | |
'All rights reserved. | |
#Region "References" | |
Imports System.Runtime.InteropServices | |
#End Region | |
Friend Class NativeMethods | |
<DllImport("user32.dll")> Friend Shared Function SendMessage(wnd As IntPtr, msg As Integer, param As Boolean, lparam As Integer) As Integer | |
End Function | |
End Class |
'Copyright (c) Smart PC Utilities, Ltd. | |
'All rights reserved. | |
Namespace Controls | |
Public Enum ScrollBarOrientation | |
''' <summary> | |
''' Horizontal ScrollBar | |
''' </summary> | |
Horizontal | |
''' <summary> | |
''' Vertical ScrollBar | |
''' </summary> | |
Vertical | |
End Enum | |
End Namespace |
'Copyright (c) Smart PC Utilities, Ltd. | |
'All rights reserved. | |
Public Enum UITheme As Integer | |
''' <summary> | |
''' User defined style | |
''' </summary> | |
Custom = -1 | |
''' <summary> | |
''' Visual Studio 2019 Dark Blue style | |
''' </summary> | |
VS2019DarkBlue = 0 | |
''' <summary> | |
''' Visual Studio 2019 Light Blue style | |
''' </summary> | |
VS2019LightBlue = 1 | |
End Enum |
Hi. It's great that you made this control. But in my project it's buggy. When I scroll, the colored scrollbar hides, and the system scrollbar is shown. Please, fix it. I want to use this scrollbar in my project, so I'm looking for to an improved version.
@Dragon-0609 The code above only aims to create a standalone ScrollBar control that supports custom themes. If you want to use this control to replace the default Control ScrollBars, see my answer on StackOverflow https://stackoverflow.com/a/73613569/5514131 of how to replace the Panel default ScrollBars with this custom ScrollBar control.
- Improved the Flat ScrollBar control to handle custom ScrollBar width and height.
Tested the example code that you wrote in StackOverflow. The default scrollbars were still there in the panel. I copied FlatPanel and added it to my form. The system scrollbars are still shown.
System info:
Windows 10
.NET Framework 4.5.2
- Fixed an issue with the Flat ScrollBar control Width property.
@Dragon-0609 I created a demo project to showcase the Flat ScrollBar control and how to use it to replace the default Panel ScrollBars.
https://1drv.ms/u/s!AvvS0P5fH-wMjVuEG2uH5bKYcmpK?e=Y81inl
https://1drv.ms/u/s!AvvS0P5fH-wMjVxTld5XO0dMU-Op?e=5bag4n
It works! I might have done something wrong.
Thanks. I'll try to use it in my project. If I achieve that, I'll notify you.
@Dragon-0609 There is no issue with your code, I have just fixed an issue with the Flat ScrollBar control.
There is no issue with your code
No, there's an issue with my code.
I'm trying to swap places of VScrollBar
(winforms) with FlatScrollBar
. I inherited VScrollBar
in FlatScrollBar
in order to swap places. It works well if I scroll with Mouse Wheels, but if I scroll by holding the left button, windows scroll popups up and hides FlatScrollBar
.
@Dragon-0609 I have improved the FlatPanel control:
- Used the WndProc instead of OnPaint to show/update the custom scrollbars, and handled the WM_NCCALCSIZE message to show/hide the custom scrollbars, this will prevent the default scrollbars from appearing.
- Used the Parent property instead of the FindForm function to add the custom scrollbar controls, this will improve the positioning of the custom scrollbars.
See the updated FlatPanel control https://gist.github.com/ahmedosama007/39f8b76e65300e5969110b753fe0a654
@ahmedosama007 I saw the updated code, but it isn't what I'm looking for. I don't use FlatPanel. I use FlatScrollBar.
Here's the VScrollBar that I want to swap places.
I can just swap places via a plugin, not that code itself.
Hi. It's great that you made this control.
But in my project it's buggy.
When I scroll, the colored scrollbar hides, and the system scrollbar is shown. Please, fix it.
I want to use this scrollbar in my project, so I'm looking forward to an improved version.