Imports System.Drawing
Imports System.Drawing.Text
Imports System.Drawing.Imaging
Imports System.Drawing.Drawing2D
Imports System.Windows.Forms

Public Class ImageMenuItem

    'MenuItenクラスを継承
    Inherits MenuItem

    'テキストレイアウトのタブストップに使用する
    'Single型変数を宣言し、初期値を格納
    Protected sinOffset As Single = 100
    Protected sinDat() As Single = New Single() {0}

    'テキストレイアウト情報を設定する
    'StringFormatクラスを宣言し、インスタンスを格納
    Protected format As StringFormat = New StringFormat

    'メニュー用のシステムフォントを格納
    Protected mFont As Font = SystemInformation.MenuFont

    Protected mImage As Image

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

    Public Sub New()
        MyBase.New()
        Call SetFormat()
    End Sub

    Public Sub New(ByVal Text As String)
        MyBase.New(Text)
        '区切り線以外の場合は初期化
        If Text <> "-" Then Call SetFormat()
    End Sub

    Public Sub New(ByVal Text As String, _
            ByVal EventHandler As EventHandler)
        MyBase.New(Text, EventHandler)
        Call SetFormat()
    End Sub

    Public Sub New(ByVal Text As String, _
            ByVal EventHandler As EventHandler, _
            ByVal ShortCut As Shortcut)
        MyBase.New(Text, EventHandler, ShortCut)
        Call SetFormat()
    End Sub

    Public Sub New(ByVal Text As String, _
            ByVal EventHandler As EventHandler, _
            ByVal ShortCut As Shortcut, _
            ByVal Image As Image)
        MyBase.New(Text, EventHandler, ShortCut)
        mImage = Image
        Call SetFormat()
    End Sub

    Protected Sub SetFormat()

        'タブストップを設定
        format.SetTabStops(sinOffset, sinDat)

        'ホットキープリフィックスを表示
        format.HotkeyPrefix = HotkeyPrefix.Show

        OwnerDraw = True

    End Sub

    Protected Overrides Sub OnMeasureItem(ByVal e As MeasureItemEventArgs)

        MyBase.OnMeasureItem(e)

        Dim strMenuItem As String = Text

        'ショートカットキーが設定されている場合は
        'タブをはさんでメニューテキストに追加
        If ShowShortcut And Shortcut <> Shortcut.None Then _
            strMenuItem = strMenuItem & ControlChars.Tab _
                            & Shortcut.ToString

        'アイテムの高さを設定
        e.ItemHeight = SystemInformation.MenuHeight

        'テキストレイアウトを指定した文字列から
        'アイテムの幅を計測し格納
        Dim intWidth As Integer = e.Graphics.MeasureString _
            (strMenuItem, mFont, Int32.MaxValue, format).Width

        'アイテムの幅を設定
        e.ItemWidth = intWidth

    End Sub

    Protected Overrides Sub OnDrawItem(ByVal e As DrawItemEventArgs)

        MyBase.OnDrawItem(e)

        'メニューテキストを格納
        Dim strMenuItem As String = Me.Text

        'ショートカットキーが設定されている場合は
        'タブをはさんでメニューテキストに追加
        If Shortcut And ShowShortcut <> Shortcut.None Then _
            strMenuItem = strMenuItem & ControlChars.Tab _
                                    & Shortcut.ToString

        '背景色のBrushオブジェクトを宣言し、
        '初期値を格納
        Dim bBackColor As Brush = SystemBrushes.Menu

        '前景色のBrushオブジェクトを宣言し、
        '初期値を格納
        Dim bForeColor As Brush = SystemBrushes.WindowText

        '枠線のPenオブジェクトを宣言し、
        '初期値を格納
        Dim p As Pen = New Pen(SystemColors.Menu)

        'MenuItemの境界を表す四角形を取得し格納
        Dim rect As Rectangle = e.Bounds

        'テキストの描画位置を格納する変数を宣言し、
        '初期値を格納
        Dim intLeft As Integer = e.Bounds.Left + 22

        '使用不可の場合
        If e.State And DrawItemState.Grayed Then

            '前景色のブラシを変更
            bForeColor = New SolidBrush(SystemColors.GrayText)

        End If

        'ルートメニューの場合
        If IsRootMenu(Me.Parent.GetType) Then

            'テキストの描画位置を変更
            Dim intWidth As Integer = e.Graphics.MeasureString _
                (strMenuItem, mFont, Int32.MaxValue, format).Width
            intLeft = e.Bounds.Left + (e.Bounds.Width - intWidth) / 2

            '背景色と枠線の色を変更
            bBackColor = SystemBrushes.Control
            p = New Pen(SystemColors.Control)

        End If

        '選択状態の場合
        If e.State And DrawItemState.Selected Then

            'グラデーションブラシを格納
            bBackColor = New LinearGradientBrush _
                        (rect, Color.FromArgb(255, 240, 200), _
                        Color.FromArgb(255, 220, 160), _
                        LinearGradientMode.Vertical)

            p = New Pen(Color.FromArgb(100, 100, 100))

            '背景色を描画
            e.Graphics.FillRectangle(bBackColor, rect)

            '枠線の大きさをセット
            rect.Height -= 1
            rect.Width -= 1

            '枠線を描画
            e.Graphics.DrawRectangle(p, rect)

        Else    '選択されていない場合

            'ルートメニューではない場合
            If Not IsRootMenu(Me.Parent.GetType) Then

                '背景色を描画
                e.Graphics.FillRectangle(bBackColor, rect)

                '左側の背景色領域を宣言
                Dim lrect As Rectangle = _
                    New Rectangle(rect.X, rect.Y, 20, rect.Height)

                'グラデーションブラシを格納
                bBackColor = New LinearGradientBrush _
                            (lrect, Color.FromArgb(220, 235, 250), _
                            Color.FromArgb(150, 180, 240), _
                            LinearGradientMode.Horizontal)

                '背景色を描画
                e.Graphics.FillRectangle(bBackColor, lrect)
            Else

                '背景色を描画
                e.Graphics.FillRectangle(bBackColor, rect)

            End If

        End If

        DrawImage(e)

        '文字列を描画
        e.Graphics.DrawString(strMenuItem, mFont, _
            bForeColor, intLeft, e.Bounds.Top + 4, format)

    End Sub

    '領域にイメージを描画
    Private Sub DrawImage(ByVal e As DrawItemEventArgs)

        Dim iLeft As Integer = e.Bounds.Left + 2
        Dim iTop As Integer = e.Bounds.Top + 2
        Dim unit As GraphicsUnit = GraphicsUnit.Pixel
        Dim imgA As New ImageAttributes

        'カラー調整行列を作成（各色に対し30％減色）
        Dim clrMtrxE As Single()() = { _
           New Single() {0.7F, 0, 0, 0, 0}, _
           New Single() {0, 0.7F, 0, 0, 0}, _
           New Single() {0, 0, 0.7F, 0, 0}, _
           New Single() {0, 0, 0, 1, 0}, _
           New Single() {0, 0, 0, 0, 1}}

        'カラーマトリクスのインスタンスを作成
        Dim clrMtrx As New ColorMatrix(clrMtrxE)

        'カラー調整行列を設定
        imgA.SetColorMatrix(clrMtrx, ColorMatrixFlag.Default, _
                            ColorAdjustType.Bitmap)

        'イメージが設定されている場合
        If Not mImage Is Nothing Then

            Dim rect As Rectangle = _
                New Rectangle(iLeft, iTop, mImage.Width, mImage.Height)

            '使用不可の場合
            If e.State And DrawItemState.Grayed Then
                '減色したイメージを描画
                e.Graphics.DrawImage(mImage, rect, 0, 0, _
                                    mImage.Width, mImage.Height, unit, imgA)
            Else
                e.Graphics.DrawImage(mImage, iLeft, iTop)
            End If

        End If

    End Sub

    'ルートメニューであるか否かの判定
    Private Function IsRootMenu(ByVal t As Type) As Boolean

        If t Is (New OfficeMenu).GetType Then

            Return True

        End If

    End Function

End Class
