Community
Showing results for 
Search instead for 
Do you mean 
Reply

Add proper looking context menu item

Copper Contributor
Posts: 10
Country: Canada

Add proper looking context menu item

Hi,

 

I have no problem adding my own menu item to any given context menu, however, it does not suit the look and feel of act! (see picture)

 

Any ideas?

 

menu.png

 

^ Test is my inserted item.. looking really non-act!-ish Smiley Sad

 

Copper Elite Contributor
Posts: 81
Country: Canada

Re: Add proper looking context menu item

[ Edited ]

I ran into a similar problem this week and after searching for a while, I had to end up writing my own DrawMenu and MeasureMenu methods if I wanted  the menu options looking like Act.

 

Basically, right now, your menu is being drawn by windows, and it doesn't know the custom desgin code Act uses (the icon area in gray, rest is white background, blue highlight border etc etc)

 

You need to set the OwnerDraw property of the menu item to true, and add eventhandlers to the DrawItem and MeasureItem.

 

Here's the code that helped me quite a bit with drawing: http://www.codeproject.com/Articles/4332/Putting-Images-Next-To-MenuItems-In-A-Menu-in-C

 

 

I still have to mess around with mine but it looks close enough at the moment.

 

Untitled2.png

 

Ahsan Khalid

Chief Technology Officer
Keystroke Quality Computing Inc.
www.keystroke.ca

Bronze Super Contributor
Posts: 1,231
Country: USA

Re: Add proper looking context menu item

Here are two classes you can use to mimic the act! menu style. One is for an icon menu item and the second is for a seperator menu item

 

Usage Example:

Friend Shared WithEvents GroupTreeViewMenu As System.Windows.Forms.MenuItem

 

GroupTreeViewMenu = New IconMenuItem("Group Tree", CType(GetEmbeddedIcon("TreeView16.ico"), Icon), New EventHandler(AddressOf OnMenuItemClick), Nothing)

 

 

Public Class IconMenuItem : Inherits System.Windows.Forms.MenuItem

    Private m_Icon As Icon
    Private m_Font As Font
    Private m_Checked As Boolean


    Public Sub New(ByVal text As String, ByVal icon As Icon, ByVal onClick As EventHandler, ByVal shortcut As Windows.Forms.Shortcut)
        MyBase.New(text, onClick, shortcut)
        OwnerDraw = True
        m_Font = New Font("Microsoft Sans Serif", 8)
        m_Checked = False
        m_Icon = icon
    End Sub

    Public Overloads Sub Dispose()
        m_Font.Dispose()
        m_Font = Nothing
        m_Icon.Dispose()
        m_Icon = Nothing
        MyBase.Dispose()
    End Sub

    Public Property Icon() As Icon
        Get
            Return m_Icon
        End Get
        Set(ByVal value As Icon)
            m_Icon = value
        End Set
    End Property

    Public Property isChecked() As Boolean
        Get
            Return MyBase.Checked
        End Get
        Set(ByVal value As Boolean)
            MyBase.Checked = value
        End Set
    End Property

    Protected Overrides Sub OnMeasureItem(ByVal e As Windows.Forms.MeasureItemEventArgs)
        Dim sf As StringFormat = New StringFormat

        sf.HotkeyPrefix = Drawing.Text.HotkeyPrefix.Show
        sf.SetTabStops(60, New Single() {0})

        MyBase.OnMeasureItem(e)

        e.ItemHeight = 22
        e.ItemWidth = CInt(e.Graphics.MeasureString(GetRealText(), m_Font, 10000, sf).Width) + 10
        sf.Dispose()
        sf = Nothing
    End Sub

    Private Function AppendShortcut() As String 'Basicaly determines to draw the HeldButtton+AnyKey thing. 
        Dim sTemp As String
        sTemp = Me.Text
        If Me.ShowShortcut And Me.Shortcut <> Windows.Forms.Shortcut.None Then
            Dim kKeys As Windows.Forms.Keys = CType(Shortcut, Windows.Forms.Keys)
            sTemp = sTemp & Convert.ToChar(9) & System.ComponentModel.TypeDescriptor.GetConverter(GetType(Windows.Forms.Keys)).ConvertToString(kKeys)
        End If
        Return sTemp
    End Function

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

            Dim br As Brush
            Dim fDisposeBrush As Boolean

            If CBool(e.State And Windows.Forms.DrawItemState.Selected) Then

                ' Highlighted / Mouse Hover

                ' Left Rectangle
                Dim rcLeft As Rectangle = e.Bounds
                rcLeft.Width = 24

                ' Right Rectangle
                Dim rcBk As Rectangle = e.Bounds

                ' Draw the rectangle around the menu border
                Dim rcBorder As Rectangle = e.Bounds
                rcBorder.Y += 3
                rcBorder.Width -= 2
                rcBorder.Height -= 4

                'br = New Drawing2D.LinearGradientBrush(rcBorder, SystemColors.Highlight, SystemColors.Control, 0)
                fDisposeBrush = True

                ' Blue-ish Color for the highlight
                br = New SolidBrush(Color.FromArgb(100, 122, 150, 222))
                ' Draw the border
                e.Graphics.FillRectangle(br, rcBorder)
                ' Draw the highlighted menu 
                e.Graphics.DrawRectangle(New Pen(New SolidBrush(Color.FromArgb(0, 0, 255))), rcBorder)

                If isChecked Then
                    e.Graphics.DrawIcon(CType(GetEmbeddedIcon("MenuChecked.ico"), Icon), e.Bounds.Left + 5, e.Bounds.Top + 5)
                Else
                    ' Box under the icon
                    If Not m_Icon Is Nothing Then
                        e.Graphics.DrawIcon(m_Icon, e.Bounds.Left + 5, e.Bounds.Top + 5)
                    End If

                End If

                
            Else
                ' NOT highlighted 

                ' Left Rectangle
                Dim rcLeft As Rectangle = e.Bounds
                rcLeft.Width = 24
                'rcLeft.Y += 1 ' 

                ' Right Rectangle
                Dim rcBk As Rectangle = e.Bounds
                rcBk.X += 24 ' Move over 24 pixels
                'rcBk.Y += 1 ' 

                ' Box under the icon
                e.Graphics.FillRectangle(SystemBrushes.Control, rcLeft)

                If isChecked Then
                    e.Graphics.DrawIcon(CType(GetEmbeddedIcon("MenuChecked.ico"), Icon), e.Bounds.Left + 5, e.Bounds.Top + 5)
                Else
                    If Not m_Icon Is Nothing Then
                        e.Graphics.DrawIcon(m_Icon, e.Bounds.Left + 5, e.Bounds.Top + 5)
                    End If

                End If

                br = SystemBrushes.Menu
                e.Graphics.FillRectangle(br, rcBk)

            End If

            ' Only Dispose the brush if we created it, 
            ' not if it was retrieved from SystemBrushes
            If fDisposeBrush Then br.Dispose()
            br = Nothing

            ' Draw the text last ( Always black )
            Dim sf As StringFormat = New StringFormat
            sf.HotkeyPrefix = Drawing.Text.HotkeyPrefix.Show
            sf.SetTabStops(60, New Single() {0})
            br = New SolidBrush(Color.Black)
            e.Graphics.DrawString(GetRealText(), m_Font, br, e.Bounds.Left + 27, e.Bounds.Top + 5, sf)
            br.Dispose()
            br = Nothing
            sf.Dispose()
            sf = Nothing
        Catch ex As Exception
            ' do nothing
        End Try

    End Sub

    Private Function GetRealText() As String
        Try
            Dim s As String = Text

            ' Append shortcut if one is set and it should be visible
            If ShowShortcut And Shortcut <> Windows.Forms.Shortcut.None Then
                ' To get a string representation of a Shortcut value, cast
                ' it into a Keys value and use the KeysConverter class (via TypeDescriptor).
                Dim k As Windows.Forms.Keys = CType(Shortcut, Windows.Forms.Keys)
                's = s & Convert.ToChar(9) &  TypeDescriptor.GetConverter(GetType(Windows.Forms.Keys)).ConvertToString(k)
            End If

            Return s
        Catch ex As Exception
            ' do nothing
        End Try
        Return Text
    End Function

    Public Shared Function GetEmbeddedIcon(ByVal strName As String) As Icon
        Dim sAssemblAndResourceName As String = String.Empty
        sAssemblAndResourceName = System.Reflection.Assembly.GetExecutingAssembly.GetName.Name + "." + strName
        Return New Icon(System.Reflection.Assembly.GetExecutingAssembly.GetManifestResourceStream(sAssemblAndResourceName.Substring(sAssemblAndResourceName.IndexOf(".") + 1)))
    End Function

End Class   ' IconMenuItem

Public Class SeperatorMenuItem : Inherits System.Windows.Forms.MenuItem

    Private m_Font As Font

    Public Sub New(ByVal text As String)
        MyBase.New("-")
        OwnerDraw = True
        m_Font = New Font("Microsoft Sans Serif", 8)
    End Sub

    Public Overloads Sub Dispose()
        m_Font.Dispose()
        m_Font = Nothing
        MyBase.Dispose()
    End Sub

    Protected Overrides Sub OnMeasureItem(ByVal e As Windows.Forms.MeasureItemEventArgs)
        Dim sf As StringFormat = New StringFormat

        sf.HotkeyPrefix = Drawing.Text.HotkeyPrefix.Show
        sf.SetTabStops(60, New Single() {0})

        MyBase.OnMeasureItem(e)
        e.ItemHeight = 5
        e.ItemWidth = CInt(e.Graphics.MeasureString(GetRealText(), m_Font, 10000, sf).Width) + 10
        sf.Dispose()
        sf = Nothing
    End Sub

    Private Function AppendShortcut() As String 'Basicaly determines to draw the HeldButtton+AnyKey thing. 
        Dim sTemp As String
        sTemp = Me.Text
        If Me.ShowShortcut And Me.Shortcut <> Windows.Forms.Shortcut.None Then
            Dim kKeys As Windows.Forms.Keys = CType(Shortcut, Windows.Forms.Keys)
            sTemp = sTemp & Convert.ToChar(9) & System.ComponentModel.TypeDescriptor.GetConverter(GetType(Windows.Forms.Keys)).ConvertToString(kKeys)
        End If
        Return sTemp
    End Function

    Protected Overrides Sub OnDrawItem(ByVal e As Windows.Forms.DrawItemEventArgs)

        Try
            MyBase.OnDrawItem(e)

            Dim br As Brush
            Dim fDisposeBrush As Boolean

            If CBool(e.State And Windows.Forms.DrawItemState.Selected) Then

                ' Highlighted / Mouse Hover

                ' Left Rectangle
                Dim rcLeft As Rectangle = e.Bounds
                rcLeft.Width = 24

                ' Right Rectangle
                Dim rcBk As Rectangle = e.Bounds

                ' Draw the rectangle around the menu border
                Dim rcBorder As Rectangle = e.Bounds
                rcBorder.Y += 3
                rcBorder.Width -= 2
                rcBorder.Height -= 4

                'br = New Drawing2D.LinearGradientBrush(rcBorder, SystemColors.Highlight, SystemColors.Control, 0)
                fDisposeBrush = True

                ' Bluish Color for the highlight
                br = New SolidBrush(Color.FromArgb(100, 122, 150, 222))
                ' Draw the border
                e.Graphics.FillRectangle(br, rcBorder)
                ' Drae the highlighted menu 
                e.Graphics.DrawRectangle(New Pen(New SolidBrush(Color.FromArgb(0, 0, 255))), rcBorder)

            Else
                ' NOT highlighted 

                ' Left Rectangle
                Dim rcLeft As Rectangle = e.Bounds
                rcLeft.Width = 24

                ' Right Rectangle
                Dim rcBk As Rectangle = e.Bounds
                rcBk.X += 28 ' Move over 28 pixels
                rcBk.Y += 3 ' Mpve down 3 pixe3ls

                ' Box under the icon
                e.Graphics.FillRectangle(SystemBrushes.Control, rcLeft)

                br = SystemBrushes.Menu
                'e.Graphics.FillRectangle(br, rcBk)

                'rcBk.Height = 1
                e.Graphics.DrawLine(New Pen(New SolidBrush(Color.FromArgb(172, 168, 153))), rcBk.X, rcBk.Y, rcBk.X + rcBk.Width, rcBk.Y)
            End If

            ' Only Dispose the brush if we created it, 
            ' not if it was retrieved from SystemBrushes
            If fDisposeBrush Then br.Dispose()
            br = Nothing

            ' Draw the text last ( Always black )
            Dim sf As StringFormat = New StringFormat
            sf.HotkeyPrefix = Drawing.Text.HotkeyPrefix.Show
            sf.SetTabStops(60, New Single() {0})
            br = New SolidBrush(Color.Black)
            e.Graphics.DrawString(GetRealText(), m_Font, br, e.Bounds.Left + 27, e.Bounds.Top + 5, sf)
            br.Dispose()
            br = Nothing
            sf.Dispose()
            sf = Nothing
        Catch ex As Exception
            ' do nothing
        End Try

    End Sub

    Private Function GetRealText() As String
        Try
            Dim s As String = Text

            ' Append shortcut if one is set and it should be visible
            If ShowShortcut And Shortcut <> Windows.Forms.Shortcut.None Then
                ' To get a string representation of a Shortcut value, cast
                ' it into a Keys value and use the KeysConverter class (via TypeDescriptor).
                Dim k As Windows.Forms.Keys = CType(Shortcut, Windows.Forms.Keys)
                's = s & Convert.ToChar(9) &  TypeDescriptor.GetConverter(GetType(Windows.Forms.Keys)).ConvertToString(k)
            End If

            Return "____________________" 's
        Catch ex As Exception
            ' do nothing
        End Try

        Return Text

    End Function

End Class   ' SeperatorMenuItem

 

Copper Super Contributor
Posts: 112
Country: Australia

Re: Add proper looking context menu item

i would have to search some of my code, but im sure that the menus are built with Infragistics controls..

 

I just imported the reference to Infragistics and with a few lines of code create a menu item, then added it to the menu.. was simple and straight forward.. of course if they stop using Infragistics then the menu items in a newer ACT version might not work, but for all the current versions it works fine