Files
staxrip/UI/Controls/Controls.vb
T
2016-03-14 03:24:20 +01:00

2037 lines
66 KiB
VB.net

Imports System.Reflection
Imports System.ComponentModel
Imports System.IO
Imports System.Runtime.InteropServices
Imports System.Drawing.Drawing2D
Imports System.Windows.Forms.VisualStyles
Imports System.Text
Imports System.Text.RegularExpressions
Imports System.Drawing.Design
Imports System.Threading
Imports System.Threading.Tasks
Namespace UI
Public Class TreeViewEx
Inherits TreeView
Private AutoCollapsValue As Boolean
<DefaultValue(False)>
Property AutoCollaps As Boolean
<DefaultValue(GetType(TreeNodeExpandMode), "Disabled")>
Property ExpandMode As TreeNodeExpandMode
<DefaultValue(False)>
Property SelectOnMouseDown() As Boolean
Protected Overrides Sub OnAfterSelect(e As TreeViewEventArgs)
If AutoCollaps Then
For Each i As TreeNode In If(e.Node.Parent Is Nothing, Nodes, e.Node.Parent.Nodes)
If Not i Is e.Node Then
i.Collapse()
End If
Next
End If
Select Case ExpandMode
Case TreeNodeExpandMode.Normal
e.Node.Expand()
Case TreeNodeExpandMode.InclusiveChilds
e.Node.ExpandAll()
End Select
MyBase.OnAfterSelect(e)
End Sub
Protected Overrides Sub WndProc(ByRef m As Message)
If SelectOnMouseDown AndAlso m.Msg = Native.WM_LBUTTONDOWN Then
Dim n = GetNodeAt(ClientMousePos)
If Not n Is Nothing AndAlso n.Nodes.Count = 0 Then
SelectedNode = n
Focus()
Exit Sub
End If
End If
MyBase.WndProc(m)
End Sub
Sub MoveSelectionLeft()
Dim n As TreeNode = SelectedNode
If Not n Is Nothing AndAlso Not n.Parent Is Nothing Then
Dim parentParentNodes As TreeNodeCollection = GetParentParentNodes(n)
Dim parentIndex As Integer = n.Parent.Index
If Not parentParentNodes Is Nothing Then
n.Remove()
parentParentNodes.Insert(parentIndex + 1, n)
SelectedNode = n
End If
End If
End Sub
Sub MoveSelectionUp()
Dim n As TreeNode = SelectedNode
If Not n Is Nothing Then
If n.Index = 0 Then
Dim parentParentNodes As TreeNodeCollection = GetParentParentNodes(n)
If Not parentParentNodes Is Nothing Then
Dim index As Integer = n.Parent.Index
n.Remove()
parentParentNodes.Insert(index, n)
End If
Else
Dim index As Integer = n.Index
Dim parentNodes As TreeNodeCollection = GetParentNodes(n)
n.Remove()
parentNodes.Insert(index - 1, n)
End If
SelectedNode = n
End If
End Sub
Sub MoveSelectionRight()
Dim n As TreeNode = SelectedNode
If Not n Is Nothing Then
If n.Index > 0 Then
Dim previousNode As TreeNode = n.PrevNode
n.Remove()
previousNode.Nodes.Add(n)
SelectedNode = n
End If
End If
End Sub
Sub MoveSelectionDown()
Dim n As TreeNode = SelectedNode
If Not n Is Nothing Then
If n.NextNode Is Nothing Then
Dim parentParentNodes As TreeNodeCollection = GetParentParentNodes(n)
If Not parentParentNodes Is Nothing Then
Dim index As Integer = n.Parent.Index
n.Remove()
parentParentNodes.Insert(index + 1, n)
End If
Else
Dim index As Integer = n.Index
Dim parentNodes As TreeNodeCollection = GetParentNodes(n)
n.Remove()
parentNodes.Insert(index + 1, n)
End If
SelectedNode = n
End If
End Sub
Private Function GetParentParentNodes(n As TreeNode) As TreeNodeCollection
Dim parent = n.Parent
If parent Is Nothing Then
Return Nothing
End If
If parent.Parent Is Nothing Then
Return Nodes
Else
Return parent.Parent.Nodes
End If
End Function
Private Function GetParentNodes(n As TreeNode) As TreeNodeCollection
Dim parent As TreeNode = n.Parent
If parent Is Nothing Then
Return Nodes
Else
Return parent.Nodes
End If
End Function
Protected Overrides Sub OnHandleCreated(e As EventArgs)
MyBase.OnHandleCreated(e)
Native.SetWindowTheme(Handle, "explorer", Nothing)
End Sub
Function AddNode(path As String) As TreeNode
Dim pathElements = path.SplitNoEmptyAndWhiteSpace("|")
Dim currentNodeList = Nodes
Dim currentPath = ""
Dim ret As TreeNode = Nothing
For Each iNodeName In pathElements
If currentPath <> "" Then
currentPath += "|"
End If
currentPath += iNodeName
Dim found = False
For Each iNode As TreeNode In currentNodeList
If iNode.Text = iNodeName Then
ret = iNode
currentNodeList = iNode.Nodes
found = True
End If
Next
If Not found Then
ret = New TreeNode
ret.Text = iNodeName
currentNodeList.Add(ret)
currentNodeList = ret.Nodes
End If
Next
Return ret
End Function
Function GetNodes() As List(Of TreeNode)
Dim ret As New List(Of TreeNode)
AddNodesRecursive(Nodes, ret)
Return ret
End Function
Shared Sub AddNodesRecursive(searchList As TreeNodeCollection, returnList As List(Of TreeNode))
For Each i As TreeNode In searchList
returnList.Add(i)
AddNodesRecursive(i.Nodes, returnList)
Next
End Sub
End Class
Public Enum TreeNodeExpandMode
Disabled
Normal
InclusiveChilds
End Enum
Public Class ToolStripEx
Inherits ToolStrip
Sub New()
MyBase.New()
End Sub
Sub New(ParamArray items As ToolStripItem())
MyBase.New(items)
End Sub
<DefaultValue(False), Description("Overdraws a weird grey line visible at the bottom in some configurations.")>
Property OverdrawLine As Boolean
<DefaultValue(False), Description("Only one button can be checked at the same time.")>
Property SingleAutoChecked As Boolean
<DefaultValue(False), Description("Shows a themed control border.")>
Property ShowControlBorder As Boolean
Protected Overrides Sub OnPaint(e As PaintEventArgs)
MyBase.OnPaint(e)
If OverdrawLine Then
Dim b As New SolidBrush(BackColor)
e.Graphics.FillRectangle(b, 0, Height - 2, Width, 2)
b.Dispose()
End If
If ShowControlBorder AndAlso VisualStyleInformation.IsEnabledByUser Then
ControlPaint.DrawBorder(e.Graphics,
ClientRectangle,
VisualStyleInformation.TextControlBorder,
ButtonBorderStyle.Solid)
End If
End Sub
Protected Overrides Sub OnItemClicked(e As ToolStripItemClickedEventArgs)
If SingleAutoChecked Then
For Each i In Items.OfType(Of ToolStripButton)()
If i Is e.ClickedItem Then
i.Checked = True
Else
i.Checked = False
End If
Next
End If
MyBase.OnItemClicked(e)
End Sub
Protected Overrides ReadOnly Property CreateParams() As CreateParams
Get
Dim ret = MyBase.CreateParams
If ShowControlBorder AndAlso Not VisualStyleInformation.IsEnabledByUser Then
ret.ExStyle = ret.ExStyle Or Native.WS_EX_CLIENTEDGE
End If
Return ret
End Get
End Property
End Class
Public Class LineControl
Inherits Control
Public Sub New()
Margin = New Padding(4, 2, 5, 2)
Anchor = AnchorStyles.Left Or AnchorStyles.Bottom Or AnchorStyles.Right
SetStyle(ControlStyles.SupportsTransparentBackColor, True)
End Sub
Protected Overrides Sub OnPaint(e As PaintEventArgs)
Dim textOffset As Integer
Dim lineHeight = CInt(Height / 2)
If Text <> "" Then
Dim textSize = e.Graphics.MeasureString(Text, Font)
textOffset = CInt(textSize.Width)
Using b = New SolidBrush(If(Enabled, ForeColor, SystemColors.GrayText))
e.Graphics.DrawString(Text, Font, b, 0, CInt((Height - textSize.Height) / 2) - 1)
End Using
End If
If Enabled Then
e.Graphics.DrawLine(Pens.Silver, textOffset, lineHeight, Width, lineHeight)
e.Graphics.DrawLine(Pens.White, textOffset, lineHeight + 1, Width, lineHeight + 1)
Else
e.Graphics.DrawLine(SystemPens.InactiveBorder, textOffset, lineHeight, Width, lineHeight)
End If
MyBase.OnPaint(e)
End Sub
End Class
Public Class CommandLink
Inherits Button
Const BS_COMMANDLINK As Integer = &HE
Const BCM_SETSHIELD As Integer = &H160C
Const BCM_SETNOTE As Integer = &H1609
Const BCM_GETNOTE As Integer = &H160A
Const BCM_GETNOTELENGTH As Integer = &H160B
Sub New()
Me.FlatStyle = FlatStyle.System
End Sub
Protected Overloads Overrides ReadOnly Property CreateParams() As CreateParams
Get
Dim r = MyBase.CreateParams
r.Style = r.Style Or BS_COMMANDLINK
Return r
End Get
End Property
Private NoteValue As String = ""
<DefaultValue("")>
Property Note() As String
Get
Return NoteValue
End Get
Set(value As String)
Native.SendMessage(Handle, BCM_SETNOTE, 0, value)
NoteValue = value
End Set
End Property
Protected Overrides Sub OnCreateControl()
If OK(Note) Then
Text += CrLf2 + Note
End If
MyBase.OnCreateControl()
End Sub
End Class
Public Class TextBoxEx
Inherits TextBox
<DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)>
Property ValidationFunc As Func(Of String, Boolean)
<DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)>
Shadows Property Name() As String
Get
Return MyBase.Name
End Get
Set(value As String)
MyBase.Name = value
End Set
End Property
<DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)>
Shadows Property TabIndex() As Integer
Get
Return MyBase.TabIndex
End Get
Set(value As Integer)
MyBase.TabIndex = value
End Set
End Property
Protected Overrides Sub OnValidating(e As CancelEventArgs)
If Not ValidationFunc Is Nothing Then
e.Cancel = Not ValidationFunc.Invoke(Text)
End If
MyBase.OnValidating(e)
End Sub
End Class
Public Class PanelEx
Inherits Panel
Private ShowNiceBorderValue As Boolean
Sub New()
SetStyle(ControlStyles.ResizeRedraw, True)
End Sub
<DefaultValue(False), Description("Nicer border if themes are enabled.")>
Property ShowNiceBorder() As Boolean
Get
Return ShowNiceBorderValue
End Get
Set(Value As Boolean)
ShowNiceBorderValue = Value
Invalidate()
End Set
End Property
Protected Overrides Sub OnPaint(e As PaintEventArgs)
MyBase.OnPaint(e)
If ShowNiceBorder AndAlso VisualStyleInformation.IsEnabledByUser Then
ControlPaint.DrawBorder(e.Graphics, ClientRectangle,
VisualStyleInformation.TextControlBorder, ButtonBorderStyle.Solid)
End If
End Sub
End Class
Public Class CheckBoxEx
Inherits CheckBox
<DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)>
Shadows Property Name() As String
Get
Return MyBase.Name
End Get
Set(value As String)
MyBase.Name = value
End Set
End Property
<DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)>
Shadows Property TabIndex() As Integer
Get
Return MyBase.TabIndex
End Get
Set(value As Integer)
MyBase.TabIndex = value
End Set
End Property
End Class
Public Class RichTextBoxEx
Inherits RichTextBox
Property BlockPaint As Boolean
Private BorderRect As Native.RECT
Sub New(Optional cms As ContextMenuStrip = Nothing)
If VisualStyleInformation.IsEnabledByUser Then
BorderStyle = BorderStyle.None
End If
If cms Is Nothing Then
ContextMenuStrip = New ContextMenuStrip
Else
ContextMenuStrip = cms
End If
AddHandler Disposed, Sub() If Not ContextMenuStrip Is Nothing Then ContextMenuStrip.Dispose()
Dim cutItem = ContextMenuStrip.Items.Add("Cut")
Dim copyItem = ContextMenuStrip.Items.Add("Copy")
Dim pasteItem = ContextMenuStrip.Items.Add("Paste")
AddHandler cutItem.Click, Sub()
Clipboard.SetText(SelectedText)
SelectedText = ""
End Sub
AddHandler copyItem.Click, Sub() Clipboard.SetText(SelectedText)
AddHandler pasteItem.Click, Sub() Paste()
AddHandler ContextMenuStrip.Opening, Sub()
cutItem.Enabled = SelectionLength > 0 AndAlso Not [ReadOnly]
copyItem.Enabled = SelectionLength > 0
pasteItem.Enabled = Clipboard.GetText <> "" AndAlso Not [ReadOnly]
End Sub
End Sub
Protected Overrides Sub WndProc(ByRef m As Message)
Const WM_NCPAINT = &H85
Const WM_NCCALCSIZE = &H83
Const WM_THEMECHANGED = &H31A
Select Case m.Msg
Case Native.WM_PAINT, Native.WM_ERASEBKGND
If BlockPaint Then Exit Sub
Case Else
End Select
MyBase.WndProc(m)
Select Case m.Msg
Case WM_NCPAINT
WmNcpaint(m)
Case WM_NCCALCSIZE
WmNccalcsize(m)
Case WM_THEMECHANGED
UpdateStyles()
End Select
End Sub
Private Sub WmNccalcsize(ByRef m As Message)
If Not VisualStyleInformation.IsEnabledByUser Then Return
Dim par As New Native.NCCALCSIZE_PARAMS()
Dim windowRect As Native.RECT
If m.WParam <> IntPtr.Zero Then
par = CType(Marshal.PtrToStructure(m.LParam, GetType(Native.NCCALCSIZE_PARAMS)), Native.NCCALCSIZE_PARAMS)
windowRect = par.rgrc0
End If
Dim clientRect = windowRect
clientRect.Left += 1
clientRect.Top += 1
clientRect.Right -= 1
clientRect.Bottom -= 1
BorderRect = New Native.RECT(clientRect.Left - windowRect.Left,
clientRect.Top - windowRect.Top,
windowRect.Right - clientRect.Right,
windowRect.Bottom - clientRect.Bottom)
If m.WParam = IntPtr.Zero Then
Marshal.StructureToPtr(clientRect, m.LParam, False)
Else
par.rgrc0 = clientRect
Marshal.StructureToPtr(par, m.LParam, False)
End If
Const WVR_HREDRAW = &H100
Const WVR_VREDRAW = &H200
Const WVR_REDRAW = (WVR_HREDRAW Or WVR_VREDRAW)
m.Result = New IntPtr(WVR_REDRAW)
End Sub
Private Sub WmNcpaint(ByRef m As Message)
If Not VisualStyleInformation.IsEnabledByUser Then Return
Dim r As Native.RECT
Native.GetWindowRect(Handle, r)
r.Right -= r.Left
r.Bottom -= r.Top
r.Top = 0
r.Left = 0
r.Left += BorderRect.Left
r.Top += BorderRect.Top
r.Right -= BorderRect.Right
r.Bottom -= BorderRect.Bottom
Dim hDC = Native.GetWindowDC(Handle)
Native.ExcludeClipRect(hDC, r.Left, r.Top, r.Right, r.Bottom)
Using g = Graphics.FromHdc(hDC)
g.Clear(Color.CadetBlue)
End Using
Native.ReleaseDC(Handle, hDC)
m.Result = IntPtr.Zero
End Sub
Protected Overrides Sub OnHandleCreated(e As EventArgs)
MyBase.OnHandleCreated(e)
AutoWordSelection = False
End Sub
End Class
Public Class TrackBarEx
Inherits TrackBar
Shadows Property Value As Integer
Get
Return MyBase.Value
End Get
Set(value As Integer)
If value > Maximum Then value = Maximum
If value < Minimum Then value = Minimum
If value <> MyBase.Value Then MyBase.Value = value
End Set
End Property
End Class
Public Class LabelEx
Inherits Label
Sub New()
TextAlign = Drawing.ContentAlignment.MiddleLeft
End Sub
<DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)>
Shadows Property Name() As String
Get
Return MyBase.Name
End Get
Set(value As String)
MyBase.Name = value
End Set
End Property
<DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)>
Shadows Property TabIndex() As Integer
Get
Return MyBase.TabIndex
End Get
Set(value As Integer)
MyBase.TabIndex = value
End Set
End Property
End Class
Public Class MultiFolderTree
Inherits TreeViewEx
Property Paths As List(Of String) = New List(Of String)
Sub New()
AutoCollaps = True
ExpandMode = TreeNodeExpandMode.Normal
End Sub
Sub Init()
CheckBoxes = True
Dim drives As New List(Of String)
Dim volumes As New List(Of String)
If Not DesignMode Then
For Each i As DriveInfo In DriveInfo.GetDrives
If i.DriveType = DriveType.Fixed Then
drives.Add(i.RootDirectory.Name)
Try 'user reported crash
volumes.Add(i.VolumeLabel)
Catch ex As Exception
volumes.Add(i.Name)
End Try
End If
Next
Init(Nodes, drives.ToArray, volumes)
For Each i As FolderTreeNode In Nodes
Init(i.Nodes, GetDirs(i.Path))
Next
End If
End Sub
Sub Init(nodes As TreeNodeCollection,
directories As String(),
Optional volumes As List(Of String) = Nothing)
For i = 0 To directories.Length - 1
Dim directory = directories(i)
Try
Dim di As New DirectoryInfo(directory)
If directory.Length = 3 OrElse (di.Attributes And FileAttributes.Hidden) = 0 Then
Dim n As New FolderTreeNode
n.Path = directory
If volumes Is Nothing Then
n.Text = DirPath.GetName(directory)
Else
n.Text = volumes(i) + " (" + directory.Substring(0, 2) + ")"
End If
If n.Text = "" Then
n.Text = directory
End If
nodes.Add(n)
End If
Catch
End Try
Next
End Sub
<DebuggerNonUserCode()>
Private Function GetDirs(path As String) As String()
Try
Return Directory.GetDirectories(path)
Catch ex As Exception
Return New String() {}
End Try
End Function
Protected Overrides Sub OnBeforeExpand(e As TreeViewCancelEventArgs)
MyBase.OnBeforeExpand(e)
Dim n = DirectCast(e.Node, FolderTreeNode)
For Each i As FolderTreeNode In n.Nodes
If Not i.WasInitialized Then
Init(i.Nodes, GetDirs(i.Path))
i.WasInitialized = True
End If
Next
End Sub
Protected Overrides Sub OnAfterCheck(e As TreeViewEventArgs)
Dim n = DirectCast(e.Node, FolderTreeNode)
If e.Node.Checked Then
Paths.Add(n.Path)
Else
Paths.Remove(n.Path)
End If
MyBase.OnAfterCheck(e)
End Sub
Protected Overrides Sub OnClick(e As EventArgs)
MyBase.OnClick(e)
Dim n = GetNodeAt(ClientMousePos)
If Not n Is Nothing AndAlso (n.Nodes.Count = 0 OrElse
n.IsExpanded) AndAlso n.Bounds.Contains(ClientMousePos) Then
n.Checked = Not n.Checked
End If
End Sub
End Class
Public Class FolderTreeNode
Inherits TreeNode
Public Path As String
Public WasInitialized As Boolean
End Class
Public Class BeforeShowControlEventArgs
Inherits EventArgs
Public Control As Control
Public Position As Point
Public Cancel As Boolean
End Class
Public Class PropertyGridEx
Inherits PropertyGrid
Sub New()
ToolbarVisible = False 'GridView is not ready when PropertySortChanged happens so Init fails
End Sub
Protected Overrides Sub OnSelectedGridItemChanged(e As SelectedGridItemChangedEventArgs)
MyBase.OnSelectedGridItemChanged(e)
Dim help = e.NewSelection.PropertyDescriptor.Description
If help <> "" Then
HelpVisible = True
Dim lines = CInt(Math.Ceiling(CreateGraphics.MeasureString(
help, Font, Width).Height / Font.Height))
Dim r As New Reflector(Me, GetType(PropertyGrid))
Dim doc = r.Invoke("doccomment")
doc.Invoke("Lines", lines + 1)
doc.Invoke("userSized", True)
r.Invoke("OnLayoutInternal", False)
Else
HelpVisible = False
End If
End Sub
Sub MoveSplitter(x As Integer)
Dim grid As New Reflector(Me, GetType(PropertyGrid))
grid.Invoke("gridView").Invoke("MoveSplitterTo", x)
End Sub
End Class
<DefaultEvent("LinkClick")>
Public Class LinkGroupBox
Inherits GroupBox
Public WithEvents ll As New LinkLabel
Event LinkClick()
Sub New()
ll.Left = 8
ll.AutoSize = True
Controls.Add(ll)
End Sub
Overrides Property Text() As String
Get
Return ll.Text
End Get
Set(value As String)
ll.Text = value
End Set
End Property
Private Sub Label_Click() Handles ll.Click
ShowContext()
RaiseEvent LinkClick()
End Sub
Private Sub ShowContext()
If Not ll.ContextMenuStrip Is Nothing Then
ll.ContextMenuStrip.Show(ll, 0, 16)
End If
End Sub
End Class
Public Class CheckedListBoxEx
Inherits CheckedListBox
<DefaultValue(CStr(Nothing))> Property UpButton As Button
<DefaultValue(CStr(Nothing))> Property DownButton As Button
<DefaultValue(CStr(Nothing))> Property RemoveButton As Button
Event ItemsChanged()
Sub OnItemsChanged()
RaiseEvent ItemsChanged()
End Sub
Sub MoveSelectedItemUp()
Dim i = SelectedIndex
If i > 0 Then
Dim state = GetItemChecked(i)
Items.Insert(i - 1, SelectedItem)
Items.RemoveAt(i + 1)
SelectedIndex = i - 1
SetItemChecked(SelectedIndex, state)
OnItemsChanged()
End If
End Sub
Sub MoveSelectedItemDown()
Dim i = SelectedIndex
If i < Items.Count - 1 Then
Dim state = GetItemChecked(i)
Items.Insert(i + 2, SelectedItem)
Items.RemoveAt(i)
SelectedIndex = i + 1
SetItemChecked(SelectedIndex, state)
OnItemsChanged()
End If
End Sub
Sub RemoveSelection()
Dim i = SelectedIndex
Items.Remove(SelectedItem)
OnItemsChanged()
If Items.Count > i Then
SelectedIndex = i
Else
If Items.Count > 0 Then
SelectedIndex = Items.Count - 1
End If
End If
End Sub
Protected Overrides Sub OnSelectedIndexChanged(e As EventArgs)
MyBase.OnSelectedIndexChanged(e)
UpdateControls()
End Sub
Sub UpdateControls()
If Not RemoveButton Is Nothing Then RemoveButton.Enabled = Not SelectedItem Is Nothing
If Not UpButton Is Nothing Then UpButton.Enabled = SelectedIndex > 0
If Not DownButton Is Nothing Then DownButton.Enabled = SelectedIndex < Items.Count - 1 AndAlso SelectedIndex >= 0
End Sub
Protected Overrides Sub OnCreateControl()
MyBase.OnCreateControl()
If Not DesignMode Then
If Not UpButton Is Nothing Then UpButton.AddClickAction(AddressOf MoveSelectedItemUp)
If Not DownButton Is Nothing Then DownButton.AddClickAction(AddressOf MoveSelectedItemDown)
If Not RemoveButton Is Nothing Then RemoveButton.AddClickAction(AddressOf RemoveSelection)
End If
End Sub
End Class
Public Class MenuButton
Inherits ButtonEx
Event ValueChangedUser(value As Object)
Property Menu As New ContextMenuStrip
Public Sub New()
Menu.ShowImageMargin = False
ShowMenuSymbol = True
AddHandler Menu.Opening, AddressOf MenuOpening
End Sub
Sub MenuOpening(sender As Object, e As CancelEventArgs)
Menu.MinimumSize = New Size(Width, 0)
For Each i As ActionMenuItem In Menu.Items
If Not Value Is Nothing AndAlso Value.Equals(i.Tag) Then
i.Font = New Font(i.Font, FontStyle.Bold)
Else
i.Font = New Font(i.Font, FontStyle.Regular)
End If
If (Menu.Width - i.Width) > 2 Then
i.AutoSize = False
i.Width = Menu.Width - 1
End If
Next
End Sub
Private ValueValue As Object
<DefaultValue(CStr(Nothing))>
Property Value As Object
Get
Return ValueValue
End Get
Set(value As Object)
If Menu.Items.Count = 0 Then
If TypeOf value Is System.Enum Then
For Each i In System.Enum.GetValues(value.GetType)
Dim text = DispNameAttribute.GetValueForEnum(i)
Dim temp = i
ActionMenuItem.Add(Menu.Items, text, Sub(o As Object) OnAction(text, o), temp, Nothing).Tag = temp
Next
End If
End If
If Not value Is Nothing Then
For Each i In Menu.Items.OfType(Of ActionMenuItem)()
If value.Equals(i.Tag) Then Text = i.Text
Next
End If
If Text = "" AndAlso Not value Is Nothing Then
Text = value.ToString
End If
ValueValue = value
End Set
End Property
Protected Overrides Sub OnMouseDown(e As MouseEventArgs)
If e.Button = MouseButtons.Left Then
Menu.Show(Me, 0, Height)
Else
MyBase.OnMouseDown(e)
End If
End Sub
Protected Overridable Sub OnValueChanged(value As Object)
RaiseEvent ValueChangedUser(value)
End Sub
Sub Add(items As IEnumerable(Of Object))
For Each i In items
Add(i.ToString, i, Nothing)
Next
End Sub
Sub Add(path As String, obj As Object, Optional tip As String = Nothing)
Dim name = path
If path.Contains("|") Then name = path.RightLast("|").Trim
ActionMenuItem.Add(Menu.Items, path, Sub(o As Object) OnAction(name, o), obj, tip).Tag = obj
End Sub
Private Sub OnAction(text As String, value As Object)
Me.Text = text
Me.Value = value
OnValueChanged(value)
End Sub
Function GetValue(Of T)() As T
Return DirectCast(Value, T)
End Function
Function GetInt() As Integer
Return DirectCast(Value, Integer)
End Function
Protected Overrides Sub Dispose(disposing As Boolean)
Menu.Dispose()
MyBase.Dispose(disposing)
End Sub
End Class
Public Class CmdlRichTextBox
Inherits RichTextBoxEx
Public Sub New()
Font = New Font("Tahoma", 9, FontStyle.Regular)
End Sub
Property LastCmdl As String
Sub SetText(cmdl As String)
If cmdl = LastCmdl Then
Exit Sub
End If
If Not OK(cmdl) Then
Text = ""
LastCmdl = ""
Exit Sub
End If
BlockPaint = True
Text = cmdl
SelectAll()
SelectionColor = ForeColor
SelectionFont = New Font(Font, FontStyle.Regular)
If LastCmdl <> "" Then
Dim selStart = GetCompareIndex(cmdl, LastCmdl)
Dim selEnd = cmdl.Length - GetCompareIndex(ReverseString(cmdl), ReverseString(LastCmdl))
If selEnd > selStart AndAlso selEnd - selStart < cmdl.Length - 1 Then
While selStart > 0 AndAlso selStart + 1 < cmdl.Length AndAlso
Not cmdl(selStart - 1) + cmdl(selStart) = " -"
selStart = selStart - 1
End While
If selEnd - selStart < 25 Then
SelectionStart = selStart
If selEnd - selStart = cmdl.Length Then
SelectionLength = 0
Else
SelectionLength = selEnd - selStart
End If
SelectionFont = New Font(Font, FontStyle.Bold)
End If
End If
End If
SelectionStart = cmdl.Length
BlockPaint = False
Refresh()
LastCmdl = cmdl
End Sub
Function GetCompareIndex(a As String, b As String) As Integer
For x = 0 To a.Length - 1
If x > b.Length - 1 OrElse x > a.Length - 1 OrElse a(x) <> b(x) Then
Return x
End If
Next
Return 0
End Function
Function ReverseString(value As String) As String
Dim a = value.ToCharArray
Array.Reverse(a)
Return New String(a)
End Function
End Class
Public Class StockIconLinkLabel
Inherits LinkLabel
Private Img As Image
Public Sub New()
Padding = New Padding(18, 0, 0, 0)
MinimumSize = New Size(18, 18)
End Sub
<DefaultValue(GetType(StockIconIdentifier), "Info")>
Property Icon As StockIconIdentifier = StockIconIdentifier.Info
Protected Overrides Sub OnPaint(e As PaintEventArgs)
MyBase.OnPaint(e)
If Img Is Nothing Then
Img = StockIcon.GetSmallImage(Icon)
End If
If Not Img Is Nothing Then
e.Graphics.DrawImage(Img, 0, 0)
End If
End Sub
End Class
Public Class WikiLinkLabel
Inherits LinkLabel
Private MarkupValue As String
<Editor(GetType(StringEditor), GetType(UITypeEditor))>
Public Property Markup As String
Get
Return MarkupValue
End Get
Set(value As String)
MarkupValue = value
Links.Clear()
If value.Contains("[") Then
Dim re As New Regex("\[(.+?) (.+?)\]")
While True
Dim m = re.Match(value)
If m.Success Then
Links.Add(m.Index, m.Groups(2).Value.Length, m.Groups(1).Value)
value = value.Replace(m.Value, m.Groups(2).Value)
Else
Exit While
End If
End While
End If
Text = value
End Set
End Property
<Browsable(False),
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)>
Public Overrides Property Text As String
Get
Return MyBase.Text
End Get
Set(value As String)
MyBase.Text = value
End Set
End Property
Protected Overrides Sub OnLinkClicked(e As LinkLabelLinkClickedEventArgs)
Dim t = e.Link.LinkData.ToString
If t.StartsWith("mailto:") OrElse t.StartsWith("http://") Then
Process.Start(t)
End If
MyBase.OnLinkClicked(e)
End Sub
End Class
<ProvideProperty("Expand", GetType(Control))>
Class FlowLayoutPanelEx
Inherits FlowLayoutPanel
Implements IExtenderProvider
<DefaultValue(False)>
Property UseParenWidth As Boolean
Property AutomaticOffset As Boolean
<Browsable(False)>
<DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)>
Property ExpandedControls As New Dictionary(Of Control, Boolean)
Sub New()
WrapContents = False
End Sub
<DefaultValue(False)>
<DisplayName("Expand")>
Function GetExpand(c As Control) As Boolean
Return ExpandedControls.ContainsKey(c) AndAlso ExpandedControls(c)
End Function
<DisplayName("Expand")>
Sub SetExpand(c As Control, value As Boolean)
ExpandedControls(c) = value
PerformLayout()
End Sub
Sub Expand(c As Control)
SetExpand(c, True)
End Sub
Protected Overrides Sub OnLayout(levent As LayoutEventArgs)
MyBase.OnLayout(levent)
If Not WrapContents AndAlso FlowDirection = FlowDirection.LeftToRight Then
Dim nextPos As Integer
For Each i As Control In Controls
If nextPos = 0 Then
nextPos = 3
End If
If i.Visible Then
nextPos += i.Margin.Left + i.Width + i.Margin.Right
If ExpandedControls.Keys.Contains(i) AndAlso
ExpandedControls(i) Then
Dim diff = Aggregate i2 In Controls.OfType(Of Control)() Into Sum(If(i2.Visible, i2.Width + i2.Margin.Left + i2.Margin.Right, 0))
If i.AutoSize Then
nextPos += Width - diff
Else
i.Width += Width - diff
nextPos += Width - diff
End If
End If
End If
Dim index = Controls.IndexOf(i)
If index < Controls.Count - 1 Then
Dim c = Controls(index + 1)
c.Left = nextPos
End If
Next
End If
'vertical align middles
If Not WrapContents AndAlso
(FlowDirection = FlowDirection.LeftToRight OrElse
FlowDirection = FlowDirection.RightToLeft) Then
For Each i As Control In Controls
Dim offset = 0
If TypeOf i Is CheckBox Then
offset = 1
End If
i.Top = CInt((Height - i.Height) / 2) + offset
Next
End If
Dim labelBlocks = From block In Controls.OfType(Of SimpleUI.LabelBlock)() Where block.Label.Offset = 0
If labelBlocks.Count > 0 Then
Dim hMax = Aggregate i In labelBlocks Into Max(TextRenderer.MeasureText(i.Label.Text, i.Label.Font).Width)
For Each i In labelBlocks
i.Label.Offset = CInt(Math.Ceiling(hMax / i.Label.Font.Height))
Next
End If
End Sub
Protected Overrides ReadOnly Property DefaultMargin As Padding
Get
Return New Padding(0)
End Get
End Property
Public Overrides Function GetPreferredSize(proposedSize As Size) As Size
Dim ret = MyBase.GetPreferredSize(proposedSize)
If UseParenWidth Then
ret.Width = Parent.Width
End If
Return ret
End Function
End Class
Public Class ButtonEx
Inherits Button
<DefaultValue(False)>
Property ShowMenuSymbol As Boolean
<DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)>
Property ClickAction As Action
Public Sub New()
MyBase.UseVisualStyleBackColor = True
End Sub
<DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)>
Shadows Property Name() As String
Get
Return MyBase.Name
End Get
Set(value As String)
MyBase.Name = value
End Set
End Property
<DefaultValue(0), Browsable(False),
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)>
Shadows Property TabIndex() As Integer
Get
Return MyBase.TabIndex
End Get
Set(value As Integer)
MyBase.TabIndex = value
End Set
End Property
<DefaultValue(True), Browsable(False),
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)>
Shadows Property UseVisualStyleBackColor() As Boolean
Get
Return True
End Get
Set(value As Boolean)
End Set
End Property
Protected Overrides ReadOnly Property DefaultSize As Size
Get
Return New Size(100, 36)
End Get
End Property
Protected Overrides Sub OnClick(e As EventArgs)
If Not ClickAction Is Nothing Then
ClickAction.Invoke()
End If
If Not ContextMenuStrip Is Nothing Then
ContextMenuStrip.Show(Me, 0, Height)
End If
MyBase.OnClick(e)
End Sub
<DefaultValue(GetType(Image), Nothing)>
Property ZoomImage As Image
Protected Overrides Sub OnPaint(e As PaintEventArgs)
MyBase.OnPaint(e)
If ShowMenuSymbol Then
Dim _text = "6"
Dim _font = New Font("Marlett", Font.Size)
Dim textSize = e.Graphics.MeasureString(_text, _font)
Dim x = If(Text <> "", Width - textSize.Width, Math.Ceiling((Width - textSize.Width) / 2))
Dim y = Math.Ceiling((Height - textSize.Height) / 2)
Dim brush = If(Enabled, Brushes.Black, SystemBrushes.GrayText)
e.Graphics.DrawString(_text, _font, brush, CSng(x), CSng(y))
End If
If Not ZoomImage Is Nothing Then
Dim rect As New Rectangle(Padding.Left,
Padding.Top,
Width - Padding.Horizontal,
Height - Padding.Vertical)
Dim targetPoint As Point
Dim targetSize As Size
Dim sizeToFit = ZoomImage.Size
Dim ar1 = rect.Width / rect.Height
Dim ar2 = sizeToFit.Width / sizeToFit.Height
If ar2 < ar1 Then
targetSize.Height = rect.Height
targetSize.Width = CInt(sizeToFit.Width / (sizeToFit.Height / rect.Height))
targetPoint.X = CInt((rect.Width - targetSize.Width) / 2) + Padding.Left
targetPoint.Y = Padding.Top
Else
targetSize.Width = rect.Width
targetSize.Height = CInt(sizeToFit.Height / (sizeToFit.Width / rect.Width))
targetPoint.Y = CInt((rect.Height - targetSize.Height) / 2) + Padding.Top
targetPoint.X = Padding.Left
End If
If Enabled Then
e.Graphics.DrawImage(ZoomImage, New Rectangle(targetPoint, targetSize))
Else
GetType(ControlPaint).InvokeMember("DrawImageDisabled",
BindingFlags.Static Or
BindingFlags.NonPublic Or
BindingFlags.InvokeMethod,
Nothing,
Nothing,
{e.Graphics,
ZoomImage,
New Rectangle(targetPoint, targetSize),
SystemColors.Control,
False})
End If
End If
End Sub
Sub ShowBold()
Font = New Font(Font, FontStyle.Bold)
For i = 0 To 20
Application.DoEvents()
Thread.Sleep(10)
Next
Font = New Font(Font, FontStyle.Regular)
End Sub
End Class
Public Class ListBoxEx
Inherits ListBox
<DefaultValue(GetType(Button), Nothing)> Property UpButton As Button
<DefaultValue(GetType(Button), Nothing)> Property DownButton As Button
<DefaultValue(GetType(Button), Nothing)> Property RemoveButton As Button
<DefaultValue(GetType(Button), Nothing)> Property Button1 As Button
<DefaultValue(GetType(Button), Nothing)> Property Button2 As Button
Private LastTick As Long
Private KeyText As String = ""
Private BlockOnSelectedIndexChanged As Boolean
Sub UpdateSelection()
If SelectedIndex > -1 Then
BlockOnSelectedIndexChanged = True
Items(SelectedIndex) = SelectedItem
BlockOnSelectedIndexChanged = False
If Sorted Then
Sorted = False
Sorted = True
End If
End If
End Sub
Private SavedSelection As New List(Of Integer)
Sub SaveSelection()
SavedSelection.Clear()
For Each i As Integer In SelectedIndices
SavedSelection.Add(i)
Next
End Sub
Sub RestoreSelection()
For Each i In SavedSelection
SetSelected(i, True)
Next
End Sub
Sub DeleteItem(text As String)
If FindStringExact(text) > -1 Then
Items.RemoveAt(FindStringExact(text))
End If
End Sub
Sub RemoveSelection()
If SelectedIndex > -1 Then
If SelectionMode = Windows.Forms.SelectionMode.One Then
Dim index As Integer = SelectedIndex
If Items.Count - 1 > SelectedIndex Then
SelectedIndex += 1
Else
SelectedIndex -= 1
End If
Items.RemoveAt(index)
Else
Dim iFirst As Integer = SelectedIndex
Dim indices(SelectedIndices.Count - 1) As Integer
SelectedIndices.CopyTo(indices, 0)
SelectedIndex = -1
For i As Integer = indices.Length - 1 To 0 Step -1
Items.RemoveAt(indices(i))
Next
If iFirst > Items.Count - 1 Then
SelectedIndex = Items.Count - 1
Else
SelectedIndex = iFirst
End If
End If
End If
End Sub
Function CanMoveUp() As Boolean
Return SelectedIndices.Count > 0 AndAlso SelectedIndices(0) > 0
End Function
Function CanMoveDown() As Boolean
Return SelectedIndices.Count > 0 AndAlso SelectedIndices(SelectedIndices.Count - 1) < Items.Count - 1
End Function
Sub MoveSelectionUp()
If CanMoveUp() Then
Dim iAbove = SelectedIndices(0) - 1
If iAbove = -1 Then
Exit Sub
End If
Dim itemAbove = Items(iAbove)
Items.RemoveAt(iAbove)
Dim iLastItem = SelectedIndices(SelectedIndices.Count - 1)
Items.Insert(iLastItem + 1, itemAbove)
SetSelected(SelectedIndex, True)
End If
End Sub
Sub MoveSelectionDown()
If CanMoveDown() Then
Dim iBelow = SelectedIndices(SelectedIndices.Count - 1) + 1
If iBelow >= Items.Count Then
Exit Sub
End If
Dim itemBelow = Items(iBelow)
Items.RemoveAt(iBelow)
Dim iAbove = SelectedIndices(0) - 1
Items.Insert(iAbove + 1, itemBelow)
SetSelected(SelectedIndex, True)
End If
End Sub
Sub KeyDownSequence(e As KeyEventArgs)
If Environment.TickCount - LastTick > 1000 Then
KeyText = Convert.ToChar(e.KeyValue).ToString()
Else
KeyText += Convert.ToChar(e.KeyValue).ToString()
End If
For i As Integer = 0 To Items.Count - 1
If Items(i).ToString().ToLower().StartsWith(KeyText.ToLower) Then
Application.DoEvents()
SelectedIndex = -1
SelectedIndex = i
Exit For
End If
Next
LastTick = Environment.TickCount
End Sub
Sub DrawNumbered(e As DrawItemEventArgs)
If e.Index > -1 Then
e.DrawBackground()
e.DrawFocusRectangle()
Dim sb As SolidBrush = New SolidBrush(ForeColor)
Dim pf As PointF
If e.Index > 998 Then
pf = New PointF(e.Bounds.Left + 40, e.Bounds.Top)
Else
If e.Index > 98 Then
pf = New PointF(e.Bounds.Left + 30, e.Bounds.Top)
Else
pf = New PointF(e.Bounds.Left + 20, e.Bounds.Top)
End If
End If
e.Graphics.DrawString(Items(e.Index).ToString, Font, sb, pf)
e.Graphics.DrawString((e.Index + 1).ToString, Font, sb, e.Bounds.Left, e.Bounds.Top)
End If
End Sub
Protected Overrides Sub OnCreateControl()
MyBase.OnCreateControl()
If Not DesignMode Then
If Not UpButton Is Nothing Then UpButton.AddClickAction(AddressOf MoveSelectionUp)
If Not DownButton Is Nothing Then DownButton.AddClickAction(AddressOf MoveSelectionDown)
If Not RemoveButton Is Nothing Then RemoveButton.AddClickAction(AddressOf RemoveSelection)
End If
End Sub
Protected Overrides Sub OnSelectedIndexChanged(e As EventArgs)
If Not BlockOnSelectedIndexChanged Then
MyBase.OnSelectedIndexChanged(e)
UpdateControls()
End If
End Sub
Sub UpdateControls()
If Not RemoveButton Is Nothing Then RemoveButton.Enabled = Not SelectedItem Is Nothing
If Not UpButton Is Nothing Then UpButton.Enabled = SelectedIndex > 0
If Not DownButton Is Nothing Then DownButton.Enabled = SelectedIndex < Items.Count - 1
If Not Button1 Is Nothing Then Button1.Enabled = Not SelectedItem Is Nothing
If Not Button2 Is Nothing Then Button2.Enabled = Not SelectedItem Is Nothing
End Sub
End Class
Class NumEdit
Inherits UserControl
WithEvents TextBox As New Edit
Private UpControl As New Button(True)
Private DownControl As New Button(False)
Private BorderColor As Color = Color.CadetBlue
Event ValueChanged(numEdit As NumEdit)
Sub New()
SetStyle(ControlStyles.Opaque Or ControlStyles.ResizeRedraw, True)
TextBox.BorderStyle = BorderStyle.None
TextBox.TextAlign = HorizontalAlignment.Center
TextBox.Text = "0"
Controls.Add(TextBox)
Controls.Add(UpControl)
Controls.Add(DownControl)
UpControl.ClickAction = Sub() Value += Increment
DownControl.ClickAction = Sub() Value -= Increment
AddHandler UpControl.MouseDown, Sub() Focus()
AddHandler DownControl.MouseDown, Sub() Focus()
AddHandler TextBox.LostFocus, Sub() UpdateText()
AddHandler TextBox.GotFocus, Sub() SetColor(Color.CornflowerBlue)
AddHandler TextBox.LostFocus, Sub() SetColor(Color.CadetBlue)
AddHandler TextBox.MouseWheel, AddressOf Wheel
End Sub
Sub Wheel(sender As Object, e As MouseEventArgs)
If e.Delta > 0 Then
Value += Increment
Else
Value -= Increment
End If
End Sub
Private Sub SetColor(c As Color)
BorderColor = c
Invalidate()
End Sub
Protected Overridable Sub OnValueChanged(numEdit As NumEdit)
RaiseEvent ValueChanged(Me)
End Sub
Protected Overrides Sub OnLayout(levent As LayoutEventArgs)
UpControl.Width = CInt(ClientSize.Height * 0.7)
UpControl.Height = (ClientSize.Height \ 2) - 2
UpControl.Top = 2
UpControl.Left = ClientSize.Width - UpControl.Width - 2
DownControl.Width = UpControl.Width
DownControl.Left = UpControl.Left
DownControl.Top = UpControl.Height + 3
DownControl.Height = ClientSize.Height - UpControl.Height - 5
TextBox.Top = (ClientSize.Height - TextBox.Height) \ 2
TextBox.Left = 2
TextBox.Width = DownControl.Left - 3
TextBox.Height = TextRenderer.MeasureText("gG", TextBox.Font).Height
MyBase.OnLayout(levent)
End Sub
Protected Overrides Sub OnPaint(e As PaintEventArgs)
Dim r = ClientRectangle
r.Inflate(-1, -1)
e.Graphics.FillRectangle(If(Enabled, Brushes.White, SystemBrushes.Control), r)
If VisualStyleInformation.IsEnabledByUser Then
ControlPaint.DrawBorder(e.Graphics, ClientRectangle, BorderColor, ButtonBorderStyle.Solid)
Else
ControlPaint.DrawBorder3D(e.Graphics, ClientRectangle, Border3DStyle.Sunken)
End If
MyBase.OnPaint(e)
End Sub
Protected Overrides ReadOnly Property DefaultSize() As Size
Get
Return New Size(100, 36)
End Get
End Property
<Category("Data")>
<DefaultValue(GetType(Decimal), "-2147483648")>
Public Property Minimum As Decimal = -2147483648
<Category("Data")>
<DefaultValue(GetType(Decimal), "2147483647")>
Public Property Maximum As Decimal = 2147483647
<Category("Data")>
<DefaultValue(GetType(Decimal), "1")>
Property Increment As Decimal = 1
Private ValueValue As Decimal
<Category("Data")>
<DefaultValue(GetType(Decimal), "0")>
Property Value As Decimal
Get
Return ValueValue
End Get
Set(value As Decimal)
SetValue(value, True)
End Set
End Property
Private DecimalPlacesValue As Integer
<Category("Data")>
<DefaultValue(0)>
Property DecimalPlaces As Integer
Get
Return DecimalPlacesValue
End Get
Set(value As Integer)
DecimalPlacesValue = value
UpdateText()
End Set
End Property
Private Sub SetValue(value As Decimal, updateText As Boolean)
If value <> ValueValue Then
If value > Maximum Then
value = Maximum
ElseIf value < Minimum Then
value = Minimum
End If
ValueValue = value
If updateText Then
Me.UpdateText()
End If
OnValueChanged(Me)
End If
End Sub
Sub UpdateText()
TextBox.SetTextWithoutTextChanged(ValueValue.ToString("F" & DecimalPlaces))
End Sub
Private Sub TextBox_KeyDown(sender As Object, e As KeyEventArgs) Handles TextBox.KeyDown
If e.KeyData = Keys.Up Then
Value += Increment
ElseIf e.KeyData = Keys.Down Then
Value -= Increment
End If
End Sub
Private Sub TextBox_TextChanged(sender As Object, e As EventArgs) Handles TextBox.TextChanged
Dim ret As Decimal
If Decimal.TryParse(TextBox.Text, ret) Then
SetValue(ret, False)
End If
End Sub
Private Class Edit
Inherits TextBox
Private BlockTextChanged As Boolean
Sub SetTextWithoutTextChanged(val As String)
BlockTextChanged = True
Text = val
BlockTextChanged = False
End Sub
Protected Overrides Sub OnTextChanged(e As EventArgs)
If Not BlockTextChanged Then
MyBase.OnTextChanged(e)
End If
End Sub
End Class
Private Class Button
Inherits Control
Private IsUp As Boolean
Private IsHot As Boolean
Private IsPressed As Boolean
Private Renderer As VisualStyleRenderer
Private LastMouseDownTick As Integer
Property ClickAction As Action
Sub New(isUp As Boolean)
Me.IsUp = isUp
TabStop = False
SetStyle(ControlStyles.Opaque Or ControlStyles.ResizeRedraw, True)
End Sub
Protected Overrides Sub OnMouseEnter(e As EventArgs)
IsHot = True
Invalidate()
MyBase.OnMouseEnter(e)
End Sub
Protected Overrides Sub OnMouseLeave(e As EventArgs)
IsHot = False
Invalidate()
MyBase.OnMouseLeave(e)
End Sub
Protected Overrides Sub OnMouseDown(e As MouseEventArgs)
IsPressed = True
Invalidate()
ClickAction.Invoke()
LastMouseDownTick = Environment.TickCount
MouseDownClicks(1000, LastMouseDownTick)
MyBase.OnMouseDown(e)
End Sub
Protected Overrides Sub OnMouseUp(e As MouseEventArgs)
IsPressed = False
Invalidate()
MyBase.OnMouseUp(e)
End Sub
Protected Overrides Sub OnPaint(e As PaintEventArgs)
If VisualStyleInformation.IsEnabledByUser Then
Dim element As VisualStyleElement
Dim disabled, hot, normal, pressed As VisualStyleElement
If IsUp Then
disabled = VisualStyleElement.Spin.Up.Disabled
hot = VisualStyleElement.Spin.Up.Hot
normal = VisualStyleElement.Spin.Up.Normal
pressed = VisualStyleElement.Spin.Up.Pressed
Else
disabled = VisualStyleElement.Spin.Down.Disabled
hot = VisualStyleElement.Spin.Down.Hot
normal = VisualStyleElement.Spin.Down.Normal
pressed = VisualStyleElement.Spin.Down.Pressed
End If
If Enabled Then
If IsPressed Then
element = pressed
ElseIf IsHot Then
element = hot
Else
element = normal
End If
Else
element = disabled
End If
If Renderer Is Nothing Then
Renderer = New VisualStyleRenderer(element)
Else
Renderer.SetParameters(element)
End If
Renderer.DrawBackground(e.Graphics, ClientRectangle)
Else
ControlPaint.DrawButton(e.Graphics,
ClientRectangle,
If(IsPressed, ButtonState.Pushed, ButtonState.Normal))
Dim text = If(IsUp, "5", "6")
Dim font = New Font("Marlett", Me.Font.Size - 1)
Dim textSize = e.Graphics.MeasureString(text, font)
Dim x = Math.Ceiling((Width - textSize.Width) / 2)
Dim y = Math.Ceiling((Height - textSize.Height) / 2)
Dim brush = If(Enabled, Brushes.Black, SystemBrushes.GrayText)
e.Graphics.DrawString(text, font, brush, CInt(x), CInt(y))
End If
MyBase.OnPaint(e)
End Sub
Async Sub MouseDownClicks(sleep As Integer, tick As Integer)
Await Task.Run(Sub() Thread.Sleep(sleep))
If IsPressed AndAlso LastMouseDownTick = tick Then
ClickAction.Invoke()
MouseDownClicks(20, tick)
End If
End Sub
End Class
End Class
Public Class TextEdit
Inherits UserControl
Public WithEvents TextBox As New TextBoxEx
Public Shadows Event TextChanged()
Private BorderColor As Color = Color.CadetBlue
Sub New()
SetStyle(ControlStyles.Opaque Or ControlStyles.ResizeRedraw, True)
TextBox.BorderStyle = BorderStyle.None
Controls.Add(TextBox)
AddHandler TextBox.GotFocus, Sub() SetColor(Color.CornflowerBlue)
AddHandler TextBox.LostFocus, Sub() SetColor(Color.CadetBlue)
AddHandler TextBox.TextChanged, Sub() RaiseEvent TextChanged()
End Sub
Private Sub SetColor(c As Color)
BorderColor = c
Invalidate()
End Sub
Private TextValue As String
<BrowsableAttribute(True)>
<DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)>
Overrides Property Text As String
Get
Return TextBox.Text
End Get
Set(value As String)
TextBox.Text = value
End Set
End Property
Protected Overrides Sub OnLayout(levent As LayoutEventArgs)
If TextBox.Multiline Then
TextBox.Top = 2
TextBox.Left = 2
TextBox.Width = ClientSize.Width - 4
TextBox.Height = ClientSize.Height - 4
Else
TextBox.Top = (ClientSize.Height - TextBox.Height) \ 2
TextBox.Left = 2
TextBox.Width = ClientSize.Width - 4
TextBox.Height = TextRenderer.MeasureText("gG", TextBox.Font).Height
End If
MyBase.OnLayout(levent)
End Sub
Protected Overrides Sub OnPaint(e As PaintEventArgs)
Dim r = ClientRectangle
r.Inflate(-1, -1)
e.Graphics.FillRectangle(If(Enabled, Brushes.White, SystemBrushes.Control), r)
ControlPaint.DrawBorder(e.Graphics, ClientRectangle, BorderColor, ButtonBorderStyle.Solid)
MyBase.OnPaint(e)
End Sub
End Class
Interface IPage
Property Node As TreeNode
Property Path As String
Property TipProvider As TipProvider
End Interface
Class DataGridViewEx
Inherits DataGridView
Function AddTextBoxColumn() As DataGridViewTextBoxColumn
Dim ret As New DataGridViewTextBoxColumn
Columns.Add(ret)
Return ret
End Function
Function AddComboBoxColumn() As DataGridViewComboBoxColumn
Dim ret As New DataGridViewComboBoxColumn
Columns.Add(ret)
Return ret
End Function
End Class
Public Class TabControlEx
Inherits TabControl
Private DragStartPosition As Point = Point.Empty
Private TabType As Type
Protected Overrides Sub OnMouseDown(e As MouseEventArgs)
DragStartPosition = New Point(e.X, e.Y)
MyBase.OnMouseDown(e)
End Sub
Protected Overrides Sub OnMouseMove(e As MouseEventArgs)
If e.Button <> MouseButtons.Left Then Return
Dim rect = New Rectangle(DragStartPosition, Size.Empty)
rect.Inflate(SystemInformation.DragSize)
Dim page = HoverTab()
If Not page Is Nothing AndAlso Not rect.Contains(e.X, e.Y) Then
TabType = page.GetType
DoDragDrop(page, DragDropEffects.All)
End If
DragStartPosition = Point.Empty
MyBase.OnMouseMove(e)
End Sub
Protected Overrides Sub OnDragOver(e As DragEventArgs)
Dim hoverTab = Me.HoverTab()
If hoverTab Is Nothing Then
e.Effect = DragDropEffects.None
Else
If e.Data.GetDataPresent(TabType) Then
e.Effect = DragDropEffects.Move
Dim dragTab = DirectCast(e.Data.GetData(TabType), TabPage)
If hoverTab Is dragTab Then Return
Dim tabRect = GetTabRect(TabPages.IndexOf(hoverTab))
tabRect.Inflate(-3, -3)
If tabRect.Contains(PointToClient(New Point(e.X, e.Y))) Then
SwapTabPages(dragTab, hoverTab)
SelectedTab = dragTab
End If
End If
End If
MyBase.OnDragOver(e)
End Sub
Private Function HoverTab() As TabPage
For index = 0 To TabCount - 1
If GetTabRect(index).Contains(PointToClient(Cursor.Position)) Then
Return TabPages(index)
End If
Next
End Function
Private Sub SwapTabPages(ByVal tp1 As TabPage, ByVal tp2 As TabPage)
Dim index1 = TabPages.IndexOf(tp1)
Dim index2 = TabPages.IndexOf(tp2)
TabPages(index1) = tp2
TabPages(index2) = tp1
End Sub
End Class
End Namespace