mirror of
https://github.com/staxrip/staxrip.git
synced 2026-10-25 10:40:41 +08:00
493 lines
14 KiB
VB.net
493 lines
14 KiB
VB.net
|
|
Imports System.Text
|
|
Imports System.Threading
|
|
Imports System.Threading.Tasks
|
|
Imports StaxRip.UI
|
|
|
|
Public Class TaskDialog(Of T)
|
|
Inherits TaskDialogBaseForm
|
|
|
|
Property CommandDefinitions As New List(Of CommandDefinition)
|
|
Property ButtonDefinitions As New List(Of ButtonDefinition)
|
|
Property SelectedValue As T
|
|
Property SelectedText As String
|
|
Property Title As String
|
|
Property Timeout As Integer
|
|
Property Symbol As Symbol
|
|
Property Content As String
|
|
Property ContentLabel As LabelEx
|
|
Property ExpandedContent As String
|
|
Property ExpandedContentLabel As LabelEx
|
|
|
|
Overloads Property Icon As TaskIcon
|
|
Overloads Property Owner As IntPtr
|
|
|
|
|
|
Public Sub New()
|
|
MyBase.New()
|
|
End Sub
|
|
|
|
Public Sub New(defaultValue As T)
|
|
MyClass.New()
|
|
SelectedValue = defaultValue
|
|
End Sub
|
|
|
|
Public Sub New(defaultText As String, defaultValue As T)
|
|
MyClass.New(defaultValue)
|
|
SelectedText = defaultText
|
|
End Sub
|
|
|
|
|
|
Sub Init()
|
|
ShowInTaskbar = False
|
|
Width = FontHeight * 22
|
|
|
|
If Content = "" AndAlso Title?.Length > 80 Then
|
|
Content = Title
|
|
Title = ""
|
|
End If
|
|
|
|
If MenuButton.Items.Count > 0 Then
|
|
MenuButton.Visible = True
|
|
|
|
For Each i In MenuButton.Items
|
|
Dim textWidth = TextRenderer.MeasureText(i.ToString, Font).Width + FontHeight * 3
|
|
|
|
If MenuButton.Width < textWidth Then
|
|
Width += textWidth - MenuButton.Width
|
|
End If
|
|
Next
|
|
End If
|
|
|
|
If Content?.Length > 1000 OrElse ExpandedContent?.Length > 1000 Then
|
|
Width = FontHeight * 35
|
|
End If
|
|
|
|
ShowIcon = False
|
|
StartPosition = FormStartPosition.CenterScreen
|
|
|
|
If Icon <> TaskIcon.None OrElse Symbol <> Symbol.None Then
|
|
pbIcon.Visible = True
|
|
End If
|
|
|
|
Select Case Icon
|
|
Case TaskIcon.Warning
|
|
pbIcon.Image = StockIcon.GetImage(StockIconIdentifier.Warning)
|
|
Case TaskIcon.Error
|
|
pbIcon.Image = StockIcon.GetImage(StockIconIdentifier.Error)
|
|
Case TaskIcon.Info
|
|
pbIcon.Image = StockIcon.GetImage(StockIconIdentifier.Info)
|
|
Case TaskIcon.Shield
|
|
pbIcon.Image = StockIcon.GetImage(StockIconIdentifier.Shield)
|
|
Case TaskIcon.Question
|
|
pbIcon.Image = StockIcon.GetImage(StockIconIdentifier.Help)
|
|
End Select
|
|
|
|
If Symbol <> Symbol.None Then
|
|
pbIcon.Image = ImageHelp.GetSymbolImage(Symbol, Nothing, 20)
|
|
End If
|
|
|
|
TitleLabel.Font = New Font("Segoe UI", 11 * s.UIScaleFactor)
|
|
TitleLabel.Text = Title
|
|
|
|
If Content <> "" Then
|
|
ContentLabel = New LabelEx
|
|
ContentLabel.Margin = New Padding(0)
|
|
ContentLabel.BorderStyle = BorderStyle.None
|
|
ContentLabel.Text = Content
|
|
paMain.Controls.Add(ContentLabel)
|
|
End If
|
|
|
|
If ExpandedContent <> "" Then
|
|
ExpandedContentLabel = New LabelEx
|
|
ExpandedContentLabel.Margin = New Padding(0)
|
|
ExpandedContentLabel.BorderStyle = BorderStyle.None
|
|
ExpandedContentLabel.Text = ExpandedContent
|
|
ExpandedContentLabel.Name = "ExpandedInformation"
|
|
blDetails.Visible = True
|
|
paMain.Controls.Add(ExpandedContentLabel)
|
|
End If
|
|
|
|
Dim firstCommandButton As CommandButton = Nothing
|
|
|
|
For Each command In CommandDefinitions
|
|
Dim cb As New CommandButton
|
|
cb.Title = command.Text
|
|
cb.Description = command.Description
|
|
cb.Tag = command
|
|
|
|
If TypeOf command.Value Is FontFamily Then
|
|
cb.Font = New Font(command.Text, Font.Size)
|
|
End If
|
|
|
|
AddHandler cb.Click, AddressOf CommandClick
|
|
paMain.Controls.Add(cb)
|
|
|
|
If firstCommandButton Is Nothing Then
|
|
firstCommandButton = cb
|
|
End If
|
|
Next
|
|
|
|
For Each i In ButtonDefinitions
|
|
If Not flpButtons.Visible Then
|
|
flpButtons.Visible = True
|
|
flpButtons.AutoSize = True
|
|
End If
|
|
|
|
Dim b As New ButtonEx
|
|
b.Text = i.Text
|
|
b.Tag = i.Value
|
|
|
|
If AcceptButton Is Nothing AndAlso i.Text = "OK" Then
|
|
AcceptButton = b
|
|
End If
|
|
|
|
flpButtons.Controls.Add(b)
|
|
i.Button = b
|
|
AddHandler b.Click, AddressOf ButtonClick
|
|
Next
|
|
|
|
If Timeout > 0 Then
|
|
g.RunTask(Sub()
|
|
Thread.Sleep(Timeout * 1000)
|
|
|
|
If Not IsDisposingOrDisposed Then
|
|
Invoke(Sub() Close())
|
|
End If
|
|
End Sub)
|
|
End If
|
|
|
|
If TypeOf SelectedValue Is DialogResult Then
|
|
If SelectedValue.Equals(DialogResult.None) Then
|
|
If ButtonDefinitions.Where(Function(i) i.Value.Equals(DialogResult.No)).Any Then
|
|
SelectedValue = CType(CObj(DialogResult.No), T)
|
|
End If
|
|
|
|
If ButtonDefinitions.Where(Function(i) i.Value.Equals(DialogResult.Cancel)).Any Then
|
|
SelectedValue = CType(CObj(DialogResult.Cancel), T)
|
|
End If
|
|
End If
|
|
|
|
Dim ok = ButtonDefinitions.Where(Function(i) i.Value.Equals(DialogResult.OK)).FirstOrDefault
|
|
|
|
If Not ok Is Nothing Then
|
|
ActiveControl = ok.Button
|
|
End If
|
|
|
|
If ActiveControl Is Nothing Then
|
|
Dim yes = ButtonDefinitions.Where(Function(i) i.Value.Equals(DialogResult.Yes)).FirstOrDefault
|
|
|
|
If Not yes Is Nothing Then
|
|
ActiveControl = yes.Button
|
|
End If
|
|
End If
|
|
End If
|
|
|
|
If ActiveControl Is Nothing Then
|
|
If firstCommandButton Is Nothing Then
|
|
ActiveControl = TitleLabel
|
|
Else
|
|
ActiveControl = firstCommandButton
|
|
End If
|
|
End If
|
|
|
|
If Owner = IntPtr.Zero Then
|
|
Owner = GetHandle()
|
|
End If
|
|
End Sub
|
|
|
|
Sub AddCommand(value As T)
|
|
AddCommand(value.ToString, Nothing, value)
|
|
End Sub
|
|
|
|
Sub AddCommand(text As String, Optional value As T = Nothing)
|
|
AddCommand(text, Nothing, value)
|
|
End Sub
|
|
|
|
Sub AddCommand(text As String, description As String, value As T)
|
|
If value Is Nothing Then
|
|
value = CType(CObj(text), T)
|
|
End If
|
|
|
|
CommandDefinitions.Add(New CommandDefinition With {.Text = text, .Description = description, .Value = value})
|
|
End Sub
|
|
|
|
Sub AddCommands(values As IEnumerable(Of T))
|
|
For Each i In values
|
|
AddCommand(i)
|
|
Next
|
|
End Sub
|
|
|
|
Sub AddButton(text As String)
|
|
AddButton(text, CType(CObj(text), T))
|
|
End Sub
|
|
|
|
Sub AddButton(text As String, value As T)
|
|
ButtonDefinitions.Add(New ButtonDefinition With {.Text = text, .Value = value})
|
|
End Sub
|
|
|
|
Sub AddButton(value As T)
|
|
ButtonDefinitions.Add(New ButtonDefinition With {.Text = value.ToString, .Value = value})
|
|
End Sub
|
|
|
|
Sub AddButtons(values As IEnumerable(Of T))
|
|
For Each i In values
|
|
AddButton(i)
|
|
Next
|
|
End Sub
|
|
|
|
WriteOnly Property Buttons As TaskButton
|
|
Set(value As TaskButton)
|
|
For Each i In {TaskButton.OK, TaskButton.Yes, TaskButton.No,
|
|
TaskButton.Cancel, TaskButton.Retry, TaskButton.Close}
|
|
|
|
If value.HasFlag(i) Then
|
|
AddButton(i.ToString, CType(CObj(GetDialogResultFromButton(i)), T))
|
|
End If
|
|
Next
|
|
End Set
|
|
End Property
|
|
|
|
Sub CommandClick(sender As Object, e As EventArgs)
|
|
Dim tag = DirectCast(sender, CommandButton).Tag
|
|
Dim cmd = DirectCast(tag, CommandDefinition)
|
|
SelectedText = If(cmd.Text = "", cmd.Description, cmd.Text)
|
|
SelectedValue = cmd.Value
|
|
Close()
|
|
End Sub
|
|
|
|
Sub ButtonClick(sender As Object, e As EventArgs)
|
|
Dim button = DirectCast(sender, ButtonEx)
|
|
SelectedText = button.Text
|
|
SelectedValue = DirectCast(button.Tag, T)
|
|
Close()
|
|
End Sub
|
|
|
|
Overrides Sub AdjustSize()
|
|
Dim h = tlpTop.Height + tlpTop.Margin.Vertical
|
|
|
|
If paMain.Controls.Count > 0 Then
|
|
Dim last = paMain.Controls(paMain.Controls.Count - 1)
|
|
h += last.Top + last.Height + last.Margin.Vertical
|
|
End If
|
|
|
|
h += spBottom.Height
|
|
|
|
If spBottom.Controls.OfType(Of Control).Where(Function(i) i.Visible).Count > 0 Then
|
|
h += spBottom.Margin.Vertical
|
|
End If
|
|
|
|
Dim fh = FontHeight
|
|
h += CInt(fh * 0.7)
|
|
|
|
Dim nonClientHeight = Height - ClientSize.Height
|
|
Dim workingArea = Screen.FromControl(Me).WorkingArea
|
|
Dim maxHeight = workingArea.Height
|
|
Dim w = ClientSize.Width
|
|
Dim secondLongestLine = GetSecondLongestLineLength()
|
|
Dim predictedWidth = CInt(secondLongestLine * fh * 0.45)
|
|
|
|
If predictedWidth > Width Then
|
|
w = predictedWidth
|
|
End If
|
|
|
|
If w > fh * 40 Then
|
|
w = fh * 40
|
|
End If
|
|
|
|
Dim ncx = Width - ClientSize.Width
|
|
Dim ncy = Height - ClientSize.Height
|
|
|
|
w += ncx
|
|
h += ncy
|
|
|
|
If h > maxHeight Then
|
|
h = maxHeight
|
|
End If
|
|
|
|
Dim l = (workingArea.Width - w) \ 2
|
|
Dim t = (workingArea.Height - h) \ 2
|
|
|
|
Native.SetWindowPos(Handle, IntPtr.Zero, l, t, w, h, 64)
|
|
End Sub
|
|
|
|
Function GetSecondLongestLineLength() As Integer
|
|
Dim list As New List(Of Integer)({51, 52})
|
|
|
|
If Content <> "" Then
|
|
For Each line In Content.Split(BR(1))
|
|
list.Add(line.Length)
|
|
Next
|
|
End If
|
|
|
|
If ExpandedContent <> "" AndAlso ExpandedContentLabel?.Height > 0 Then
|
|
For Each line In ExpandedContent.Split(BR(1))
|
|
list.Add(line.Length)
|
|
Next
|
|
End If
|
|
|
|
For Each def In CommandDefinitions
|
|
If def.Description <> "" Then
|
|
For Each line In def.Description.Split(BR(1))
|
|
list.Add(line.Length)
|
|
Next
|
|
End If
|
|
Next
|
|
|
|
For Each def In CommandDefinitions
|
|
If def.Text <> "" Then
|
|
For Each line In def.Text.Split(BR(1))
|
|
list.Add(CInt(line.Length / 11 * 9))
|
|
Next
|
|
End If
|
|
Next
|
|
|
|
list.Sort()
|
|
list.Reverse()
|
|
Return list(1)
|
|
End Function
|
|
|
|
WriteOnly Property ShowCopyButton As Boolean
|
|
Set(value As Boolean)
|
|
If value Then
|
|
blCopyMessage.Text = "Copy Message"
|
|
blCopyMessage.Visible = True
|
|
blCopyMessage.ClickAction = Sub()
|
|
g.RunSTATask(Sub()
|
|
Clipboard.SetText(GetText)
|
|
MsgInfo("Message was copied to clipboard.")
|
|
End Sub)
|
|
End Sub
|
|
End If
|
|
End Set
|
|
End Property
|
|
|
|
Function GetHandle() As IntPtr
|
|
Dim sb As New StringBuilder(500)
|
|
Dim handle = Native.GetForegroundWindow
|
|
Native.GetWindowModuleFileName(handle, sb, CUInt(sb.Capacity))
|
|
|
|
If sb.ToString.Replace(".vshost", "").Base = Application.ExecutablePath.Base Then
|
|
Return handle
|
|
End If
|
|
End Function
|
|
|
|
Function GetText() As String
|
|
Dim ret = TitleLabel.Text
|
|
|
|
If Content <> "" Then
|
|
ret += BR2 + Content
|
|
End If
|
|
|
|
If ExpandedContent <> "" Then
|
|
ret += BR2 + ExpandedContent
|
|
End If
|
|
|
|
Return ret
|
|
End Function
|
|
|
|
Shared Function GetDialogResultFromButton(button As TaskButton) As DialogResult
|
|
Select Case button
|
|
Case TaskButton.OK
|
|
Return DialogResult.OK
|
|
Case TaskButton.Cancel, TaskButton.Close
|
|
Return DialogResult.Cancel
|
|
Case TaskButton.Yes
|
|
Return DialogResult.Yes
|
|
Case TaskButton.No
|
|
Return DialogResult.No
|
|
Case TaskButton.None
|
|
Return DialogResult.None
|
|
Case TaskButton.Retry
|
|
Return DialogResult.Retry
|
|
End Select
|
|
End Function
|
|
|
|
Protected Overrides Sub OnLoad(args As EventArgs)
|
|
MyBase.OnLoad(args)
|
|
Font = New Font("Segoe UI", 9 * s.UIScaleFactor)
|
|
Dim fh = FontHeight
|
|
|
|
For Each i As ButtonEx In flpButtons.Controls
|
|
i.Height = CInt(fh * 1.5)
|
|
i.Width = fh * 5
|
|
|
|
Using g = i.CreateGraphics
|
|
Dim minWidth = CInt(g.MeasureString(i.Text, i.Font).Width + fh)
|
|
|
|
If i.Width < minWidth Then
|
|
i.Width = minWidth
|
|
End If
|
|
End Using
|
|
|
|
i.Margin = New Padding(CInt(fh * 0.4), 0, 0, 0)
|
|
Next
|
|
|
|
MenuButton.Margin = New Padding(CInt(fh * 0.7), MenuButton.Margin.Top, CInt(fh * 0.7), MenuButton.Margin.Bottom)
|
|
InputTextEdit.Margin = MenuButton.Margin
|
|
flpButtons.Margin = New Padding(0, 0, CInt(fh * 0.7), 0)
|
|
|
|
If InputTextEdit.Visible Then
|
|
ActiveControl = InputTextEdit
|
|
InputTextEdit.TextBox.SelectAll()
|
|
End If
|
|
|
|
AdjustSize()
|
|
AdjustSize()
|
|
|
|
If Owner <> IntPtr.Zero Then
|
|
Dim GWLP_HWNDPARENT = -8
|
|
SetWindowLongPtr(Handle, GWLP_HWNDPARENT, Owner)
|
|
End If
|
|
End Sub
|
|
|
|
Overloads Function Show() As T
|
|
Init()
|
|
|
|
If Application.MessageLoop Then
|
|
Using Me
|
|
ShowDialog()
|
|
End Using
|
|
Else
|
|
Application.Run(Me)
|
|
End If
|
|
|
|
Return SelectedValue
|
|
End Function
|
|
|
|
Public Class CommandDefinition
|
|
Property Text As String
|
|
Property Description As String
|
|
Property Value As T
|
|
End Class
|
|
|
|
Public Class ButtonDefinition
|
|
Property Text As String
|
|
Property Value As T
|
|
Property Button As ButtonEx
|
|
End Class
|
|
End Class
|
|
|
|
Public Enum TaskIcon
|
|
None
|
|
Info
|
|
Warning
|
|
Question
|
|
[Error]
|
|
Shield
|
|
End Enum
|
|
|
|
Public Enum TaskButton
|
|
None = 0
|
|
OK = 1
|
|
Yes = 2
|
|
No = 4
|
|
Cancel = 8
|
|
Retry = 16
|
|
Close = 32
|
|
OkCancel = OK Or Cancel
|
|
YesNo = Yes Or No
|
|
YesNoCancel = YesNo Or Cancel
|
|
RetryCancel = Retry Or Cancel
|
|
End Enum
|