Page 1 of 2

Menu Icons

Posted: Thu Apr 20, 2006 2:13 am
by srod
Hi,

a while ago I revamped some code for drawing icons in menus, but made it far too complex and awkward to use.
In need of something much simpler, I have reworked the library into something far more streamlined and easy to use.
Indeed there is only one command

Code: Select all

AddMenuIcon(WindowID(#Window), MenuItem, Text$, [iconhandle])
which replaces the PB MenuItem() command. Note, the parameter iconhandle is optional.

Example program:

Code: Select all

XIncludeFile "MenuIcons.pbi"

;Load a couple of icons. Would normally use a resource file etc.
iconopen=LoadImage_(0,"open.ico",#IMAGE_ICON,0,0,#LR_LOADFROMFILE)    
iconsave=LoadImage_(0,"save.ico",#IMAGE_ICON,0,0,#LR_LOADFROMFILE)    


If OpenWindow(0, 200, 200, 200, 100, "AddMenuIcon Example")
  CreateMenu(0, WindowID(0))
    MenuTitle("File")
      AddMenuIcon(WindowID(0),1, "New"+Chr(9)+Chr(9)+"Ctrl+N") ;No icon provided
      AddMenuIcon(WindowID(0),2,"&Open"+Chr(9)+Chr(9)+"Ctrl+O", iconopen)
      AddMenuIcon(WindowID(0),3,"Save"+Chr(9)+Chr(9)+"Ctrl+S", iconsave)
      AddMenuIcon(WindowID(0),4,"&Save As..."+Chr(9)+"Ctrl+A") ;No icon provided
      MenuBar()
      AddMenuIcon(WindowID(0),5,"Exit") ;No icon provided
    DisableMenuItem(0,3,1)
    DisableMenuItem(0,4,1)
  Repeat : Until WaitWindowEvent()=#PB_Event_CloseWindow
EndIf

;Tidy up!
DestroyIcon_(iconopen) 
DestroyIcon_(iconsave)

End
Now the include file which must reside in the same directory as the above example program for the example to run.

Code: Select all

;Menu icons.
;Stephen Rodriguez 2006.
;Purebasic 4 beta 11.

;This small 'include' file allows for some simple customising of menus.
;Whilst it uses full 'owner' drawn methods, it nevertheless only allows a developer to add
;icons to individual menu items. This is to keep things simple etc.

;Other features, such as background colours etc. can be set by changing the appropriate constants
;in this include file.


#DT_END_ELLIPSIS = $8000
#MIIM_STATE = 1

;******************************************************************************************
;CHANGE THE FOLLOWING CONSTANTS TO MAKE GLOBAL CHANGES etc.
  #Menu_SelectedTextColour=#Blue
  #Menu_SelectedBackColour=$94FF6B
  #Menu_SelectedBorder=1 ;Thickness of border.
  #Menu_IconSize=20 ;Icons are dynamically resized.
  #Menu_ItemHeight=20
  #Menu_TextColour=#Red
  #Menu_BackColour=$19F0E6
  Global Menu_Font=LoadFont(#PB_Any, "arial", 10)
;******************************************************************************************

;The following procedure takes responsibility for drawing the menu items.
Procedure MENUICONS_CallbackProc(hWnd, uMsg, wParam, lParam)
  Protected result, prop$, *lpmis.MEASUREITEMSTRUCT, *lpdis.DRAWITEMSTRUCT, menuitinf.MENUITEMINFO, itemtext$
  Protected rc.RECT, hFontOld, hdc, size.SIZE, pen, brush, oldpen, oldbrush, icontop, borderpen
  Protected temp$,len,i, tm.TEXTMETRIC
  Select uMsg
    Case #WM_MEASUREITEM ;This message is called when the menu / submenu is first created and is used to size the menu items.
      *lpmis = lParam 
      If *lpmis\CtlType = #ODT_MENU	;Don't want this to run for an owner drawn button etc!
        itemtext$=Space(255)
        GetMenuString_(GetMenu_(hWnd), *lpmis\itemid, @itemtext$,255,#MF_BYCOMMAND)
;Working out the rectangle width is complicated by the possible inclusion of tab characters.
        itemtext$=RemoveString(itemtext$,"&")
        For i = 1 To Len(itemtext$)
          If Mid(itemtext$,i,1)=Chr(9)
            len=8*(len/8+1)
          Else
            temp$+Mid(itemtext$,i,1)
            len+1
          EndIf        
        Next
        hdc = GetDC_(hWnd) 
        hFontOld = SelectObject_(hdc,FontID(Menu_Font)) 
        GetTextExtentPoint32_(hdc,temp$,Len(temp$),@size)
        GetTextMetrics_(hdc,tm)
        *lpmis\itemWidth = size\cx+(len-Len(temp$))*tm\tmAveCharWidth+#Menu_IconSize+#Menu_IconSize/2+2*#Menu_SelectedBorder-30
        *lpmis\itemHeight = #Menu_ItemHeight
;If the height chosen by the developer is too small for the text then we need to adjust it. 
        If tm\tmHeight+2*#Menu_SelectedBorder > *lpmis\itemHeight
          *lpmis\itemHeight = tm\tmHeight+2*#Menu_SelectedBorder        
        EndIf
        If #Menu_IconSize+2*#Menu_SelectedBorder > *lpmis\itemHeight
          *lpmis\itemHeight = #Menu_IconSize+2*#Menu_SelectedBorder  
        EndIf
        SelectObject_(hdc,hFontOld) 
        ReleaseDC_(hWnd,hdc)
        result = #True 
      EndIf
    Case #WM_DRAWITEM  
        *lpdis = lParam 
        If *lpdis\CtlType = #ODT_MENU	;Don't want this to run for an owner drawn button etc!
          itemtext$=Space(255)
          GetMenuString_(GetMenu_(hWnd), *lpdis\itemid, @itemtext$,255,#MF_BYCOMMAND)
          hdc = *lpdis\hDC
          SetBkMode_(hdc,#TRANSPARENT)
          hFontOld = SelectObject_(hdc,FontID(Menu_Font)) 
          GetTextExtentPoint32_(hdc,@itemtext$,Len(itemtext$),@size) 
          If *lpdis\itemState & #ODS_SELECTED 
;Check to see if the menu item is disabled.
            menuitinf\cbSize = SizeOf(MENUITEMINFO)
            menuitinf\fMask = #MIIM_STATE
            GetMenuItemInfo_(GetMenu_(hWnd), *lpdis\itemid, #False, @menuitinf)
            If menuitinf\fState & 1	= 0
              SetTextColor_(hdc,#Menu_SelectedTextColour) 
              brush=CreateSolidBrush_(#Menu_SelectedBackColour)
              If #Menu_SelectedBorder > 0
                borderpen=CreatePen_(#PS_SOLID, #Menu_SelectedBorder, 0)
              Else
                borderpen=GetStockObject_(#NULL_PEN)
              EndIf
              oldbrush = SelectObject_(hdc,brush)
              oldpen=SelectObject_(hdc,borderpen)
              Rectangle_(hdc, *lpdis\rcItem\left, *lpdis\rcItem\top, *lpdis\rcItem\right, *lpdis\rcItem\bottom)
              icontop = (*lpdis\rcItem\top+*lpdis\rcItem\bottom-#Menu_IconSize)/2
              If *lpdis\itemData ;Only draw icon if one was specified by the developer!
                DrawIconEx_(hdc,*lpdis\rcItem\left+3,icontop,*lpdis\itemData,#Menu_IconSize,#Menu_IconSize,0,0,#DI_NORMAL	) 
              EndIf
              *lpdis\rcItem\top=(*lpdis\rcItem\top+*lpdis\rcItem\bottom-size\cy)/2
              *lpdis\rcItem\right-3
              *lpdis\rcItem\left+#Menu_IconSize+#Menu_IconSize/2
              DrawText_(hdc, @itemtext$, Len(itemtext$), *lpdis\rcItem,#DT_END_ELLIPSIS|#DT_EXPANDTABS)
            EndIf
          Else 
;Check to see if the menu item is disabled.
            menuitinf\cbSize = SizeOf(MENUITEMINFO)
            menuitinf\fMask = #MIIM_STATE
            GetMenuItemInfo_(GetMenu_(hWnd), *lpdis\itemid, #False, @menuitinf)
            If menuitinf\fState & 1	= 0
              SetTextColor_(hdc,#Menu_TextColour) 
            Else
              SetTextColor_(hdc,$AEAEAE)
            EndIf
            brush=CreateSolidBrush_(#Menu_BackColour)
            borderpen=GetStockObject_(#NULL_PEN)
            oldbrush = SelectObject_(hdc,brush)
            oldpen=SelectObject_(hdc,borderpen)
            Rectangle_(hdc, *lpdis\rcItem\left, *lpdis\rcItem\top, *lpdis\rcItem\right+#Menu_SelectedBorder, *lpdis\rcItem\bottom+#Menu_SelectedBorder)
            icontop = (*lpdis\rcItem\top+*lpdis\rcItem\bottom-#Menu_IconSize)/2
            If *lpdis\itemData ;Only draw icon if one was specified by the developer!
              DrawIconEx_(hdc,*lpdis\rcItem\left+3,icontop,*lpdis\itemData,#Menu_IconSize,#Menu_IconSize,0,0,3) 
            EndIf
            *lpdis\rcItem\top=(*lpdis\rcItem\top+*lpdis\rcItem\bottom-size\cy)/2
            *lpdis\rcItem\right-3
            *lpdis\rcItem\left+#Menu_IconSize+#Menu_IconSize/2
            DrawText_(hdc, @itemtext$, Len(itemtext$), *lpdis\rcItem,#DT_END_ELLIPSIS|#DT_EXPANDTABS)
           EndIf 
;Tidy up.
          SelectObject_(hdc,oldpen)
          SelectObject_(hdc,oldbrush)
          SelectObject_(hdc,hFontOld) 
          DeleteObject_(brush) : DeleteObject_(borderpen)
          result = #True 
        EndIf
    Case #WM_DESTROY
;Free font.
      FreeFont(Menu_Font)
;Remove the window property.
      prop$="MENUICONS_oldproc"
      result = GetProp_(hwnd, @prop$)
      RemoveProp_(hWnd, @prop$)
      If result : ProcedureReturn CallWindowProc_(result, hWnd, uMsg, wParam, lParam) : EndIf
  EndSelect      
  If result=0
    prop$="MENUICONS_oldproc"
    result = CallWindowProc_(GetProp_(hwnd, @prop$), hWnd, uMsg, wParam, lParam) 
  EndIf
ProcedureReturn result
EndProcedure 


;The following procedure adds the given menu item to the list of items to be 'owner drawn'.
Procedure AddMenuIcon(hWnd, item, text$, icon=0)
  Protected prop$
  MenuItem(item, text$)
  If ModifyMenu_(GetMenu_(hWnd),item,#MF_BYCOMMAND|#MF_OWNERDRAW,item,icon)
    prop$="MENUICONS_oldproc"
    If GetProp_(hWnd, @prop$)=#Null
      SetProp_(hWnd, @prop$, GetWindowLong_(hWnd, #GWL_WNDPROC))
      SetWindowLong_(hWnd, #GWL_WNDPROC, @MENUICONS_CallbackProc()) 
    EndIf
  EndIf
EndProcedure
Note the use of colours in the example program. Menu colours can easily be changed by changing a few constants in the include file.

The thing about this is that it uses proper icon images etc. The usual alternative is to convert to a bitmap first and then 'cheat' by setting the menuitem's checked and unchecked bitmaps etc. but this just doesn't look as 'smooth' imo.

I hope it's useful in some way. :D

**Note: this particular library will not work with popup menus. It would need a few minor adjustments first, but it's not something which I am in need of!

Posted: Sat Apr 22, 2006 9:33 am
by josku_x
THis is indeed useful! Thanks! (But it's a bit toooooooooooooo large code. But, who cares? :wink: )

Posted: Sat Apr 22, 2006 10:37 am
by srod
josku_x wrote:THis is indeed useful! Thanks! (But it's a bit toooooooooooooo large code. But, who cares? :wink: )
Aye, some of it is necessary 'overhead' when using 'owner drawn' menu items / controls. The remainder is concerned with calculating icon positions etc.

Posted: Sat Apr 22, 2006 11:32 am
by Edwin Knoppert
I ever did this but using the shortcut/accelerator key the menu width could no longer be calculated properly.
I always had to add a so-so value for width.

Did you encounter this issue?

Posted: Sat Apr 22, 2006 12:33 pm
by srod
Code updated - 22/04/2006.

Edwin: yes, there does seem to be some discrepancy between the width's I return from the #WM_MEASUREITEM message and those actually passed to the #WM_DRAWITEM message. This is even after I take into account the fact that Windows adds on a small amount for the check/uncheck bitmaps. It seems to add about an extra 30 pixels to the width which I can't explain at the moment. It doesn't seem to depend on the font selected! :?

As for accelerator keys, do you mean the "&Save As..." type with the & character? If so, then it would be straight-forward enough to check for that in the #WM_MEASUREITEM message and then remove from the width calculations etc.

Posted: Sat Apr 22, 2006 4:09 pm
by Edwin Knoppert
No i meant the accelerators like Ctrl+A (which holds a tab char)
It seems this space can not be calculated, at least i haven't found a clever technique to do so.

Of course adding nn pixels will help but it's not the same.

Posted: Sat Apr 22, 2006 4:10 pm
by Edwin Knoppert
Note that i forgot how it worked but i'm aware of the issue.
I would have to dive into the code again to verify what part went wrong :)

Posted: Sat Apr 22, 2006 4:41 pm
by srod
Bloody hell, I didn't even think of that! :oops:

My code doesn't even leave a space for the tabs, let alone calculate the extra width! Doh!

Will have to think about this...

Posted: Sat Apr 22, 2006 4:51 pm
by srod
An initial look into tabs has answered my question above, Windows seems to add the equivalent of a tab character onto the width of each menu item!

My problem now is lining up the tabs.

*Edit: got it (I think!) Will have to complete tomorrow though as it's party time!
Thanks for the post Edwin, I'd completely overlooked the damn tabs!

Posted: Sat Apr 22, 2006 6:37 pm
by srod
*Update*

Now allows 'tabs' in the menu item descriptions; e.g.

Code: Select all

AddMenuIcon(WindowID(0),3,"Save"+Chr(9)+"Ctrl+S", iconsave)
The only thing is that more than one tab might be required to align all tabs with the longest menu description (see example program above). This is no big deal. It wouldn't be difficult to automate this, but it just seems like an un-necessary complication for such a simple program.

Posted: Sat Apr 22, 2006 6:51 pm
by josku_x
Thanks! Now I like it more!

Posted: Sun Apr 23, 2006 11:32 pm
by DoubleDutch
What changes would have to be made to use it with popup menus?

Posted: Mon Apr 24, 2006 12:10 am
by srod
The following works with both window menus and popups and basically just required a little extra info saving, for which I've used a linked list.

Include file:

Code: Select all

;Menu icons.
;Stephen Rodriguez 2006.
;Purebasic 4 beta 11.

;This small 'include' file allows for some simple customising of menus.
;Whilst it uses full 'owner' drawn methods, it nevertheless only allows a developer to add
;icons to individual menu items. This is to keep things simple etc.

;Other features, such as background colours etc. can be set by changing the appropriate constants
;in this include file.


Structure _MI
  menuhWnd.l
  icon.l
EndStructure

Global NewList _MenuIcons._MI()


#DT_END_ELLIPSIS = $8000
#MIIM_STATE = 1

;******************************************************************************************
;CHANGE THE FOLLOWING CONSTANTS TO MAKE GLOBAL CHANGES etc.
  #Menu_SelectedTextColour=#Blue
  #Menu_SelectedBackColour=$94FF6B
  #Menu_SelectedBorder=1 ;Thickness of border.
  #Menu_IconSize=20 ;Icons are dynamically resized.
  #Menu_ItemHeight=20
  #Menu_TextColour=#Red
  #Menu_BackColour=$19F0E6
  Global Menu_Font=LoadFont(#PB_Any, "arial", 10)
;******************************************************************************************

;The following procedure takes responsibility for drawing the menu items.
Procedure MENUICONS_CallbackProc(hWnd, uMsg, wParam, lParam)
  Protected result, prop$, *lpmis.MEASUREITEMSTRUCT, *lpdis.DRAWITEMSTRUCT, menuitinf.MENUITEMINFO, itemtext$
  Protected rc.RECT, hFontOld, hdc, size.SIZE, pen, brush, oldpen, oldbrush, icontop, borderpen
  Protected temp$,len,i, tm.TEXTMETRIC, *mi._MI
  Select uMsg
    Case #WM_MEASUREITEM ;This message is called when the menu / submenu is first created and is used to size the menu items.
      *lpmis = lParam 
      If *lpmis\CtlType = #ODT_MENU	;Don't want this to run for an owner drawn button etc!
        *mi=*lpmis\itemData
        itemtext$=Space(255)
        GetMenuString_(*mi\menuhWnd, *lpmis\itemid, @itemtext$,255,#MF_BYCOMMAND)
       hdc = GetDC_(hWnd) 
        hFontOld = SelectObject_(hdc,FontID(Menu_Font)) 
        GetTextMetrics_(hdc,tm)
        DrawText_(hDC, itemtext$, Len(itemtext$), @rc, #DT_CALCRECT | #DT_EXPANDTABS) 
        *lpmis\itemWidth = rc\right+#Menu_IconSize+#Menu_IconSize/2+4*#Menu_SelectedBorder-GetSystemMetrics_(#SM_CXMENUCHECK)
        *lpmis\itemHeight = #Menu_ItemHeight
;If the height chosen by the developer is too small for the text then we need to adjust it. 
        If tm\tmHeight+2*#Menu_SelectedBorder > *lpmis\itemHeight
          *lpmis\itemHeight = tm\tmHeight+2*#Menu_SelectedBorder        
        EndIf
        If #Menu_IconSize+2*#Menu_SelectedBorder > *lpmis\itemHeight
          *lpmis\itemHeight = #Menu_IconSize+2*#Menu_SelectedBorder  
        EndIf
        SelectObject_(hdc,hFontOld) 
        ReleaseDC_(hWnd,hdc)
        result = #True 
      EndIf
    Case #WM_DRAWITEM  
        *lpdis = lParam 
        If *lpdis\CtlType = #ODT_MENU	;Don't want this to run for an owner drawn button etc!
          *mi=*lpdis\itemData
          itemtext$=Space(255)
          GetMenuString_(*mi\menuhWnd, *lpdis\itemid, @itemtext$,255,#MF_BYCOMMAND)
          hdc = *lpdis\hDC
          SetBkMode_(hdc,#TRANSPARENT)
          hFontOld = SelectObject_(hdc,FontID(Menu_Font)) 
          GetTextExtentPoint32_(hdc,@itemtext$,Len(itemtext$),@size) 
          If *lpdis\itemState & #ODS_SELECTED 
;Check to see if the menu item is disabled.
            menuitinf\cbSize = SizeOf(MENUITEMINFO)
            menuitinf\fMask = #MIIM_STATE
            GetMenuItemInfo_(GetMenu_(hWnd), *lpdis\itemid, #False, @menuitinf)
            If menuitinf\fState & 1	= 0
              SetTextColor_(hdc,#Menu_SelectedTextColour) 
              brush=CreateSolidBrush_(#Menu_SelectedBackColour)
              If #Menu_SelectedBorder > 0
                borderpen=CreatePen_(#PS_SOLID, #Menu_SelectedBorder, 0)
              Else
                borderpen=GetStockObject_(#NULL_PEN)
              EndIf
              oldbrush = SelectObject_(hdc,brush)
              oldpen=SelectObject_(hdc,borderpen)
              Rectangle_(hdc, *lpdis\rcItem\left, *lpdis\rcItem\top, *lpdis\rcItem\right, *lpdis\rcItem\bottom)
              icontop = (*lpdis\rcItem\top+*lpdis\rcItem\bottom-#Menu_IconSize)/2
              If *mi\icon ;Only draw icon if one was specified by the developer!
                DrawIconEx_(hdc,*lpdis\rcItem\left+3,icontop,*mi\icon,#Menu_IconSize,#Menu_IconSize,0,0,#DI_NORMAL) 
              EndIf
              *lpdis\rcItem\top=(*lpdis\rcItem\top+*lpdis\rcItem\bottom-size\cy)/2
              *lpdis\rcItem\right
              *lpdis\rcItem\left+#Menu_IconSize+#Menu_IconSize/2
              DrawText_(hdc, @itemtext$, Len(itemtext$), *lpdis\rcItem,#DT_EXPANDTABS)
            EndIf
          Else 
;Check to see if the menu item is disabled.
            menuitinf\cbSize = SizeOf(MENUITEMINFO)
            menuitinf\fMask = #MIIM_STATE
            GetMenuItemInfo_(*mi\menuhWnd, *lpdis\itemid, #False, @menuitinf)
            If menuitinf\fState & 1	= 0
              SetTextColor_(hdc,#Menu_TextColour) 
            Else
              SetTextColor_(hdc,$AEAEAE)
            EndIf
            brush=CreateSolidBrush_(#Menu_BackColour)
            borderpen=CreatePen_(#PS_SOLID, #Menu_SelectedBorder, #Menu_BackColour)
            oldbrush = SelectObject_(hdc,brush)
            oldpen=SelectObject_(hdc,borderpen)
            Rectangle_(hdc, *lpdis\rcItem\left, *lpdis\rcItem\top, *lpdis\rcItem\right, *lpdis\rcItem\bottom)
            icontop = (*lpdis\rcItem\top+*lpdis\rcItem\bottom-#Menu_IconSize)/2
            If *mi\icon ;Only draw icon if one was specified by the developer!
              DrawIconEx_(hdc,*lpdis\rcItem\left+3,icontop,*mi\icon,#Menu_IconSize,#Menu_IconSize,0,0,3) 
            EndIf
            *lpdis\rcItem\top=(*lpdis\rcItem\top+*lpdis\rcItem\bottom-size\cy)/2
            *lpdis\rcItem\right
            *lpdis\rcItem\left+#Menu_IconSize+#Menu_IconSize/2
            DrawText_(hdc, @itemtext$, Len(itemtext$), *lpdis\rcItem,#DT_EXPANDTABS)
           EndIf 
;Tidy up.
          SelectObject_(hdc,oldpen)
          SelectObject_(hdc,oldbrush)
          SelectObject_(hdc,hFontOld) 
          DeleteObject_(brush) : DeleteObject_(borderpen)
          result = #True 
        EndIf
    Case #WM_DESTROY
;Free font.
      FreeFont(Menu_Font)
;Free the linked list.
      ClearList(_MenuIcons())
;Remove the window property.
      prop$="MENUICONS_oldproc"
      result = GetProp_(hwnd, @prop$)
      RemoveProp_(hWnd, @prop$)
      If result
        result = CallWindowProc_(result, hWnd, uMsg, wParam, lParam)
      EndIf
      ProcedureReturn result
  EndSelect      
  If result=0
    prop$="MENUICONS_oldproc"
    result = GetProp_(hwnd, @prop$)
    If result : ProcedureReturn CallWindowProc_(result, hWnd, uMsg, wParam, lParam) : EndIf
  EndIf
ProcedureReturn result
EndProcedure 


;The following procedure adds the given menu item to the list of items to be 'owner drawn'.
Procedure AddMenuIcon(hWnd, menuhWnd,item, text$, icon=0)
  Protected prop$
  MenuItem(item, text$)
    AddElement(_MenuIcons())
  If ModifyMenu_(menuhWnd,item,#MF_BYCOMMAND|#MF_OWNERDRAW,item,_MenuIcons())
    _MenuIcons()\menuhWnd=menuhWnd
    _MenuIcons()\icon=icon
    prop$="MENUICONS_oldproc"
    If GetProp_(hWnd, @prop$)=#Null
      SetProp_(hWnd, @prop$, GetWindowLong_(hWnd, #GWL_WNDPROC))
      SetWindowLong_(hWnd, #GWL_WNDPROC, @MENUICONS_CallbackProc()) 
    EndIf
  EndIf
EndProcedure
Example:

Code: Select all

XIncludeFile "MenuIcons.pbi" 

;Load a couple of icons. Would normally use a resource file etc. 
iconopen=LoadImage_(0,"open.ico",#IMAGE_ICON,0,0,#LR_LOADFROMFILE)    
iconsave=LoadImage_(0,"save.ico",#IMAGE_ICON,0,0,#LR_LOADFROMFILE)    


If OpenWindow(0, 200, 200, 400, 400, "Popup-Menu Example")
    menu=CreatePopupMenu(0)      ; here the creating of the pop-up menu begins...
        AddMenuIcon(WindowID(0),menu,1, "New") ;No icon provided 
        AddMenuIcon(WindowID(0),menu,2,"&Open"+Chr(9)+Chr(9)+"Ctrl+O", iconopen) 
        AddMenuIcon(WindowID(0),menu,3,"Save"+Chr(9)+Chr(9)+"Ctrl+S", iconsave) 
        AddMenuIcon(WindowID(0),menu,4,"&Save As..."+Chr(9)+"Ctrl+A") ;No icon provided 
        MenuBar() 
        AddMenuIcon(WindowID(0),menu,5,"Exit") ;No icon provided 

    Repeat
      Select WaitWindowEvent()     ; check for window events
        Case #WM_RBUTTONDOWN       ; right mouse button was clicked =>
          DisplayPopupMenu(0, WindowID(0))  ; now display the popup-menu
        Case #PB_Event_CloseWindow
          Quit = 1
      EndSelect
    Until Quit = 1
  EndIf
There still remains a slight problem with sizing the width of the menu items, but it's nothing that can't be worked around.

Posted: Mon Sep 18, 2006 12:03 am
by newbie
Amazing srod, thanks for sharing :P

Just an addition, for people wanting to get the current default system background color for the text, just use this API :

Code: Select all

Global Menu_BackColour = GetSysColor_(#COLOR_MENU)
Thanks again srod ;)

Posted: Mon Sep 18, 2006 12:10 am
by Joakim Christiansen
I didn't test your code, but if it's only this it's doing then I found an easyer way:

Code: Select all

; PicPak Generated Code
;
*unpacked = AllocateMemory(920)
UnpackMemory(?PicPak, *unpacked)
img0 = CatchImage(#PB_Any, *unpacked, 920)
;
; End of PicPak Generated Code

Normal = GrabImage(img0, #PB_Any,12,0,12,12)
Checked = GrabImage(img0, #PB_Any,0,0,12,12)

;
; ------------------------------------------------------------
;
;   PureBasic - Menu example file
;
;    (c) 2003 - Fantaisie Software
;
; ------------------------------------------------------------
;
; We just have to open a window and see when an event happen on the menu
;

If OpenWindow(0, 100, 150, 195, 260, "PureBasic - Menu")

  ;
  ; Create the menu. The indent is very important here for a good lisibility
  ;

  If CreateMenu(0, WindowID(0))
    MenuTitle("File")
      MenuItem( 1, "&Load...")
      MenuItem( 2, "Save")
      MenuItem( 3, "Save As...")
      MenuItem( 4, "Advanced View")
      MenuBar()
      OpenSubMenu("Recents")
        MenuItem( 5, "C:\Autoexec.bat")
        MenuItem( 6, "D:\Test.txt")
        OpenSubMenu("Even more !")
          MenuItem( 12, "Test")
        CloseSubMenu()
        MenuItem( 13, "C:\Ok.bat")
      CloseSubMenu()
      MenuBar()
      MenuItem( 7, "&Quit")

    MenuTitle("Edition")
      MenuItem( 8, "Cut")
      MenuItem( 9, "Copy")
      MenuItem(10, "Paste")
     
    MenuTitle("?")
      MenuItem(11, "About")

  EndIf
 
  DisableMenuItem(0, 3, 1)
  DisableMenuItem(0, 13, 1)
 
  SetMenuItemBitmaps_(MenuID(0),4,#MF_BYCOMMAND,ImageID(Normal),ImageID(Checked))
 
  ;
  ; This is the 'event loop'. All the user actions are processed here.
  ; It's very easy to understand: when an action occurs, the EventID
  ; isn't 0 and we just have to see what have happened...
  ;
 
  Repeat

    Select WaitWindowEvent()

      Case #PB_Event_Menu

        Select EventMenu()  ; To see which menu has been selected
          Case 4
            If GetMenuItemState(0, 4)
              SetMenuItemState(0,4,0)
            Else
              SetMenuItemState(0,4,1)
            EndIf

          Case 11 ; About
            MessageRequester("About", "Cool Menu example", 0)
           
          Default
            MessageRequester("Info", "MenuItem: "+Str(EventMenu()), 0)

        EndSelect

      Case #PB_Event_CloseWindow
        Quit = 1

    EndSelect

  Until Quit = 1

EndIf

End 

; PicPak Generated Code

DataSection
  PicPak:
  Data.b $4A,$43,$98,$03,$00,$00,$17,$ED,$AB,$77,$B9,$A9,$D0,$20,$69,$14,$19,$88,$12,$CA
  Data.b $08,$B0,$4A,$0C,$25,$8C,$09,$60,$05,$02,$94,$18,$08,$62,$01,$06,$81,$2D,$FA,$2F
  Data.b $F1,$4F,$E2,$67,$5C,$56,$F8,$FA,$81,$E5,$68,$B3,$3F,$BB,$F2,$F7,$6E,$DE,$D7,$FB
  Data.b $8F,$F7,$31,$50,$5F,$EF,$73,$01,$10,$62,$57,$86,$7E,$1C,$FA,$F9,$C4,$79,$6B,$78
  Data.b $30,$89,$F1,$CC,$EF,$DD,$D7,$ED,$18,$BA,$CA,$89,$31,$0D,$47,$F6,$CB,$EE,$5C,$89
  Data.b $F9,$11,$77,$AC,$B7,$3E,$FC,$9F,$05,$DB,$23,$94,$4E,$46,$B3,$55,$FD,$87,$53,$48
  Data.b $96,$1F,$C2,$F4,$DE,$19,$96,$C9,$1D,$B9,$E2,$A0,$8D,$D7,$FE,$3C,$F6,$72,$D3,$8B
  Data.b $47,$AD,$18,$BC,$72,$81,$D3,$94,$5D,$63,$C7,$FD,$C2,$1B,$3F,$D8,$BF,$7A,$07,$1E
  Data.b $D1,$68,$29,$CF,$29,$F2,$8C,$9A,$F1,$13,$9D,$B8,$FF,$75,$DD,$34,$ED,$AF,$3F,$37
  Data.b $BD,$78,$F2,$73,$DA,$77,$EF,$35,$3C,$35,$84,$C5,$70,$34,$9F,$41,$AB,$E1,$E4,$BD
  Data.b $E3,$C6,$2F,$5D,$36,$4D,$FD,$B3,$C3,$E4,$42,$0F,$7B,$93,$40,$23,$85,$BC,$49,$02
  Data.b $2E,$19,$AF,$FB,$63,$67,$DD,$42,$32,$E2,$2C,$BF,$5F,$3F,$6A,$79,$EB,$4F,$15,$21
  Data.b $8E,$42,$20,$EC,$9F,$D2,$BF,$7D,$64,$12,$CA,$87,$7F,$3E,$F3,$7A,$80,$61,$B6,$40
  Data.b $FD,$A7,$A8,$2E,$C8,$1F,$EC,$37,$1C,$A1,$E3,$DA,$60,$03,$ED,$85,$12,$50,$12,$B3
  Data.b $FF,$D8,$77,$EB,$9F,$29,$6C,$FF,$7D,$A7,$8F,$50,$B8,$8F,$94,$47,$C6,$27,$DD,$7F
  Data.b $4E,$52,$B3,$FA,$EE,$3B,$6B,$0D,$C8,$CD,$4F,$6D,$99,$10,$50,$73,$03,$E6,$45,$88
  Data.b $C5,$44,$DF,$27,$06,$60,$5C,$02,$0E,$60,$FE,$5A,$1E,$20,$25,$AB,$AC,$F8,$76,$AF
  Data.b $5E,$DB,$47,$2A,$BF,$1D,$AD,$23,$E4,$9D,$F1,$CD,$11,$E8,$04,$8A,$33,$80,$DC,$12
  Data.b $71,$C2,$F9,$27,$B6,$73,$FD,$B6,$35,$83,$1A,$5C,$11,$11,$1A,$C9,$9F,$16,$0D,$8D
  Data.b $DC,$67,$58,$06,$50,$0A,$0C,$FC,$C2,$40,$3B,$55,$E0,$18,$E2,$1A,$D2,$9B,$DD,$30
  Data.b $3C,$F8,$48,$36,$4C,$F7,$74,$04,$7B,$EE,$FE,$39,$B2,$BC,$E2,$19,$1D,$39,$E3,$48
  Data.b $30,$3B,$FC,$F3,$C8,$77,$DD,$B1,$2D,$F1,$84,$A3,$33,$C7,$B9,$A6,$7E,$D9,$18,$7C
  Data.b $91,$D2,$33,$C0,$5D,$96,$E8,$81,$FB,$4B,$7B,$8D,$90,$FF,$E9,$8F,$9B,$70,$37,$EA
  Data.b $9F,$1C,$D0,$37,$29,$97,$D2,$7A,$F1,$FE,$8A,$CF,$EE,$FA,$2C,$29,$D5,$BD,$1C,$22
  Data.b $76,$E3,$B5,$83,$B4,$1E,$4A,$F6,$8D,$EB,$9B,$54,$DB,$4B,$8E,$13,$FE,$F8,$D1,$A1
  Data.b $7E,$87,$F9,$EB,$66,$29,$DB,$4E,$7D,$35,$E7,$A7,$E7,$5B,$FF,$F4,$DE,$FE,$25,$9C
  Data.b $46,$94,$A3,$53,$F3,$FE,$E7,$4E,$FA,$BF,$FF,$E8,$BF,$F7,$AA,$23,$7F,$3D,$FC,$F8
  Data.b $69,$10,$35,$CA,$FA,$FE,$4C,$28,$55,$99,$67,$EE,$E8,$67,$DF,$39,$53,$F8,$5E,$3D
  Data.b $77,$F3,$CA,$23,$C9,$EF,$26,$C0,$68,$58,$8C,$FC,$97,$A7,$79,$47,$CA,$70,$14,$2F
  Data.b $DD,$BF,$F9,$B7,$0A,$BB,$D8,$52,$56,$93,$5E,$2D,$FB,$F3,$D5,$D7,$7D,$6F,$F4,$AC
  Data.b $50,$F4,$3A,$81,$C2,$B0,$FD,$02,$60,$C0,$58,$24,$CB,$D4,$25,$31,$A5,$62,$CC,$BF
  Data.b $C4,$3E,$B7,$00,$F3,$36,$8B,$4E,$F8,$F7,$F9,$D3,$EB,$C5,$B2,$3F,$83,$1D,$C6,$AC
  Data.b $90,$4C,$FC,$91,$C7,$06,$6C,$BF,$70,$D8,$A9,$00,$E3,$31,$B8,$FA,$F1,$C7,$84,$39
  Data.b $0F,$DE,$00,$10,$89,$F0
  PicPakend:
EndDataSection 
Code by netmaestro!
http://www.purebasic.fr/english/viewtop ... =menu+icon