﻿Option Explicit On
Option Strict On
Option Infer Off

Imports System.ComponentModel
Imports System.Drawing.Drawing2D

#Region " MenuButton "

<System.Diagnostics.DebuggerStepThrough()> _
Public Class MenuButton
    Inherits System.Windows.Forms.CheckBox

#Region " Variables "

    Private m_DrawArrow, m_SuppressRightClick As Boolean
    Private m_MenuDirection As MenuDirections

    Private WithEvents m_ContextMenuStrip As ContextMenuStrip

    Public Event DrawArrowChanged As EventHandler
    Public Event MenuDirectionChanged As EventHandler

    Private m_ArrowFont As Font

    Private Const m_ArrowFontFamily As String = "Arial"
    Private Const m_RightArrow As String = "►"
    Private Const m_LeftArrow As String = "◄"
    Private Const m_UpArrow As String = "▲"
    Private Const m_DownArrow As String = "▼"

#End Region
#Region " Constructor "

    Public Sub New()
        MyBase.New()
        MyBase.AutoSize = False
        MyBase.Appearance = Windows.Forms.Appearance.Button
        MyBase.AutoCheck = True
        MyBase.CheckAlign = ContentAlignment.MiddleLeft
        MyBase.Size = New Size(88I, 24I)
        m_ArrowFont = New Font(m_ArrowFontFamily, Me.Font.Size, Me.Font.Style, Me.Font.Unit, Me.Font.GdiCharSet, Me.Font.GdiVerticalFont)
        m_SuppressRightClick = True
        m_DrawArrow = True
        m_MenuDirection = MenuDirections.Down
    End Sub

    Protected Overrides Sub Dispose(ByVal disposing As Boolean)
        Try
            m_ArrowFont.Dispose()
        Finally
            m_ArrowFont = Nothing
            MyBase.Dispose(disposing)
        End Try
    End Sub

#End Region
#Region " Properties: DrawArrow, MenuDirection, SuppressRightClickMenu, Checked, AutoSize, Appearance, AutoCheck "

    <DefaultValue(True), Category("Menu")> _
    Public Property DrawArrow() As Boolean
        Get
            Return m_DrawArrow
        End Get
        Set(ByVal value As Boolean)
            If m_DrawArrow <> value Then
                m_DrawArrow = value
                Me.Invalidate()
                Call OnDrawArrowChanged(EventArgs.Empty)
            End If
        End Set
    End Property

    <DefaultValue(MenuDirections.Down), Category("Menu")> _
    Public Property MenuDirection() As MenuDirections
        Get
            Return m_MenuDirection
        End Get
        Set(ByVal value As MenuDirections)
            If m_MenuDirection <> value Then
                m_MenuDirection = value
                Me.Invalidate()
                Call OnMenuDirectionChanged(EventArgs.Empty)
            End If
        End Set
    End Property

    <DefaultValue(True), Category("Menu")> _
    Public Property SuppressRightClickMenu() As Boolean
        Get
            Return m_SuppressRightClick
        End Get
        Set(ByVal value As Boolean)
            If m_SuppressRightClick <> value Then
                m_SuppressRightClick = value
            End If
        End Set
    End Property

    <Browsable(False), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), _
    EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never), DefaultValue(False)> _
    Public Shadows ReadOnly Property Checked() As Boolean
        Get
            Return MyBase.Checked
        End Get
    End Property

    <DefaultValue(False), EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never), _
    DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), Browsable(False)> _
    Public Shadows ReadOnly Property AutoSize() As Boolean
        Get
            Return False
        End Get
    End Property

    <Browsable(False), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), _
    EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never), DefaultValue(Windows.Forms.Appearance.Button)> _
    Public Shadows ReadOnly Property Appearance() As Windows.Forms.Appearance
        Get
            Return Windows.Forms.Appearance.Button
        End Get
    End Property

    <Browsable(False), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), _
    EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never), DefaultValue(True)> _
    Public Shadows ReadOnly Property AutoCheck() As Boolean
        Get
            Return True
        End Get
    End Property

    <Browsable(False), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), _
    EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never), DefaultValue(ContentAlignment.MiddleLeft)> _
    Public Shadows ReadOnly Property CheckAlign() As ContentAlignment
        Get
            Return ContentAlignment.MiddleLeft
        End Get
    End Property

    <Browsable(False), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), _
    EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never), DefaultValue(ContentAlignment.MiddleLeft)> _
    Public Shadows Property CheckState() As Windows.Forms.CheckState
        Get
            Return MyBase.CheckState
        End Get
        Set(ByVal value As Windows.Forms.CheckState)
            If MyBase.CheckState <> value Then
                MyBase.CheckState = value
            End If
        End Set
    End Property

    Protected Overrides Sub OnAutoSizeChanged(ByVal e As System.EventArgs)
        MyBase.AutoSize = False
    End Sub

#End Region
#Region " PublicMethods: PerformClick "

    Public Sub PerformClick()
        MyBase.Checked = True
    End Sub

#End Region
#Region " Overrides: OnCheckedChanged, OnRightToLeftChanged, OnContextMenuStripChanged, ContextMenuStrip_Closing "

    Protected Overrides Sub OnMouseUp(ByVal mevent As System.Windows.Forms.MouseEventArgs)
        If SuppressRightClickMenu AndAlso Me.ContextMenuStrip IsNot Nothing Then Me.ContextMenuStrip.Close()
        MyBase.OnMouseUp(mevent)
    End Sub

    Protected Overrides Sub OnCheckedChanged(ByVal e As System.EventArgs)
        MyBase.OnCheckedChanged(e)
        If Me.Checked AndAlso Me.ContextMenuStrip IsNot Nothing Then
            Select Case m_MenuDirection
                Case MenuDirections.Down
                    Me.ContextMenuStrip.Show(Me, New Point(0I, Me.Height), ToolStripDropDownDirection.BelowRight)
                Case MenuDirections.Up
                    Me.ContextMenuStrip.Show(Me, New Point(0I, 0I), ToolStripDropDownDirection.AboveRight)
                Case MenuDirections.Left
                    Me.ContextMenuStrip.Show(Me, New Point(0I, 0I), ToolStripDropDownDirection.Left)
                Case MenuDirections.Right
                    Me.ContextMenuStrip.Show(Me, New Point(Me.Width, 0I), ToolStripDropDownDirection.Right)
            End Select
        Else
            MyBase.Checked = False
        End If
    End Sub

    Protected Overrides Sub OnRightToLeftChanged(ByVal e As System.EventArgs)
        MyBase.OnRightToLeftChanged(e)
        'Me.ContextMenuStrip.RightToLeft = Windows.Forms.RightToLeft.No
        Me.Invalidate()
    End Sub

    Protected Overrides Sub OnContextMenuStripChanged(ByVal e As System.EventArgs)
        MyBase.OnContextMenuChanged(e)
        m_ContextMenuStrip = Me.ContextMenuStrip
    End Sub

    Private Sub m_ContextMenuStrip_Closing(ByVal sender As Object, ByVal e As System.Windows.Forms.ToolStripDropDownClosingEventArgs) Handles m_ContextMenuStrip.Closing
        MyBase.Checked = False
    End Sub

#End Region
#Region " Protected: OnContextMenuChanged, OnFontChanged, OnPaint "

    Protected Overrides Sub OnContextMenuChanged(ByVal e As System.EventArgs)
        MyBase.OnContextMenuChanged(e)
    End Sub

    Protected Overrides Sub OnFontChanged(ByVal e As System.EventArgs)
        MyBase.OnFontChanged(e)
        m_ArrowFont.Dispose()
        m_ArrowFont = New Font(m_ArrowFontFamily, Me.Font.Size, Me.Font.Style, Me.Font.Unit, Me.Font.GdiCharSet, Me.Font.GdiVerticalFont)
    End Sub

    <System.Diagnostics.DebuggerStepThrough()> _
    Protected Overrides Sub OnPaint(ByVal pevent As System.Windows.Forms.PaintEventArgs)
        MyBase.OnPaint(pevent)
        If m_DrawArrow Then
            Dim x As Integer = 3I
            Dim ArrowToDraw As String
            Dim y As Integer
            Select Case m_MenuDirection
                Case MenuDirections.Up
                    ArrowToDraw = m_UpArrow
                Case MenuDirections.Right
                    ArrowToDraw = m_RightArrow
                Case MenuDirections.Left
                    ArrowToDraw = m_LeftArrow
                Case Else 'Down
                    ArrowToDraw = m_DownArrow
            End Select
            y = CInt(Me.Height / 2I) - CInt(pevent.Graphics.MeasureString(ArrowToDraw, m_ArrowFont).Height / 2I)
            If MyBase.RightToLeft = Windows.Forms.RightToLeft.No Then
                x = Me.Width - x - CInt(pevent.Graphics.MeasureString(ArrowToDraw, m_ArrowFont).Width)
            End If
            Using br As New SolidBrush(Me.ForeColor)
                pevent.Graphics.DrawString(ArrowToDraw, m_ArrowFont, If(Me.Enabled, br, Brushes.Gray), x, y)
            End Using
        End If
    End Sub

#End Region
#Region " EventSubs: OnDrawArrowChanged, OnMenuDirectionChanged "

    Protected Sub OnDrawArrowChanged(ByVal e As System.EventArgs)
        RaiseEvent DrawArrowChanged(Me, e)
    End Sub

    Protected Sub OnMenuDirectionChanged(ByVal e As System.EventArgs)
        RaiseEvent MenuDirectionChanged(Me, e)
    End Sub

#End Region

End Class

#End Region
#Region " MenuDirections "

Public Enum MenuDirections
    Up = 0I
    Down = 1I
    Left = 2I
    Right = 3I
End Enum

#End Region