Imports System.ComponentModel

Imports Stax

Namespace UI
    Public Class OptionListBox
        Inherits ListBox

        Private TipTargetIsTip As Boolean
        Private TipChache As New StringPair

        Public Sub New()
            DrawMode = Windows.Forms.DrawMode.OwnerDrawFixed
            ItemHeight = 20
            IntegralHeight = True
        End Sub

        Private TextOffsetValue As Integer

        <Category("OptionListBox"), DefaultValue(0)> _
        Public Property TextOffset() As Integer
            Get
                Return TextOffsetValue
            End Get
            Set(ByVal Value As Integer)
                TextOffsetValue = Value
            End Set
        End Property

        Private TipTargetValue As TipTarget

        <Browsable(False)> _
        Public Property TipTarget() As TipTarget
            Get
                Return TipTargetValue
            End Get
            Set(ByVal Value As TipTarget)
                TipTargetValue = Value
            End Set
        End Property

        Protected Overrides Sub RefreshItem(ByVal index As Integer)
            MyBase.RefreshItem(index)
        End Sub

        Protected Overrides Sub SetItemsCore(ByVal items As IList)
            MyBase.SetItemsCore(items)
        End Sub

        Protected Overrides Sub OnDrawItem(ByVal e As DrawItemEventArgs)
            MyBase.OnDrawItem(e)

            If Items.Count > 0 AndAlso e.Index > -1 Then
                Dim g As Graphics = e.Graphics
                Dim selBrush As New SolidBrush(SystemColors.Control)
                Dim backBrush As New SolidBrush(BackColor)
                Dim foreBrush As New SolidBrush(ForeColor)
                Dim isSelected As Boolean = ((e.State And DrawItemState.Selected) = DrawItemState.Selected)

                If isSelected Then
                    g.FillRectangle(selBrush, e.Bounds)
                    ControlPaint.DrawFocusRectangle(g, e.Bounds, SystemColors.Control, BackColor)
                Else
                    g.FillRectangle(backBrush, e.Bounds)
                End If

                backBrush.Dispose()
                selBrush.Dispose()
                Dim item As OptionListBoxItem = CType(Items(e.Index), OptionListBoxItem)

                If Not item.Image Is Nothing Then
                    g.DrawImage(item.Image, e.Bounds.Left, e.Bounds.Top + (ItemHeight - item.Image.Height) \ 2, 16, 16)
                End If

                g.DrawString(item.Text, Font, foreBrush, e.Bounds.Left + TextOffset, e.Bounds.Top + (ItemHeight - Font.Height) \ 2)
                foreBrush.Dispose()
            End If
        End Sub

        Protected Overrides Sub OnSelectedIndexChanged(ByVal e As EventArgs)
            MyBase.OnSelectedIndexChanged(e)
            Dim sel As OptionListBoxItem = CType(SelectedItem, OptionListBoxItem)

            If Not TipTarget Is Nothing Then
                If Not sel Is Nothing Then
                    If Not TipTargetIsTip Then
                        TipChache = TipTarget.GetTip
                    End If

                    TipTarget.Title = sel.Text
                    TipTarget.Description = sel.Description

                    TipTargetIsTip = True
                Else
                    If TipTargetIsTip Then
                        TipTarget.SetTarget(TipChache)
                        TipTargetIsTip = False
                    End If
                End If
            End If
        End Sub

        Protected Overrides Sub OnMouseMove(ByVal e As MouseEventArgs)
            MyBase.OnMouseMove(e)
            SelectAtMouse()
        End Sub

        Public Sub SelectAtMouse()
            Dim index As Integer = IndexFromPoint(PointToClient(Control.MousePosition))

            If index <> SelectedIndex Then
                SelectedIndex = index
            End If
        End Sub

        Protected Overrides Sub OnClick(ByVal e As EventArgs)
            MyBase.OnClick(e)

            Try 'wicked bug report stacktrace being inside 'SelectedItem'
                Dim item As OptionListBoxItem = DirectCast(SelectedItem, OptionListBoxItem)

                If Not item Is Nothing Then
                    item.ClickSub.Invoke()
                End If
            Catch
            End Try
        End Sub

        Protected Overrides Sub OnMouseLeave(ByVal e As EventArgs)
            SelectedItem = Nothing
            MyBase.OnMouseLeave(e)
        End Sub
    End Class

    Public Class OptionListBoxItem
        Public Sub New()
        End Sub

        Public Sub New(ByVal text As String, ByVal tag As Object, ByVal clickSub As SubDelegate)
            Me.Text = text
            Me.Tag = tag
            Me.ClickSub = clickSub
        End Sub

        Private TextValue As String

        Public Property Text() As String
            Get
                Return TextValue
            End Get
            Set(ByVal Value As String)
                TextValue = Value
            End Set
        End Property

        Private DescriptionValue As String

        Public Property Description() As String
            Get
                Return DescriptionValue
            End Get
            Set(ByVal Value As String)
                DescriptionValue = Value
            End Set
        End Property

        Private ClickSubValue As SubDelegate

        Public Property ClickSub() As SubDelegate
            Get
                Return ClickSubValue
            End Get
            Set(ByVal Value As SubDelegate)
                ClickSubValue = Value
            End Set
        End Property

        Private ImageValue As Image

        Public Property Image() As Image
            Get
                Return ImageValue
            End Get
            Set(ByVal Value As Image)
                ImageValue = Value
            End Set
        End Property

        Private TagValue As Object

        Public Property Tag() As Object
            Get
                Return TagValue
            End Get
            Set(ByVal Value As Object)
                TagValue = Value
            End Set
        End Property

        Public Overrides Function ToString() As String
            Return Text
        End Function
    End Class
End Namespace