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])
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
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
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.

**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!