
Due to the size limitation of the forum's posts, the following version of the library has very few comments.
You can download a more recent and full version (including a demo) at https://www.editions-humanis.com/downlo ... olorEx.zip
All the Zapman libraries are available at https://www.editions-humanis.com/downlo ... ads_EN.htm
If you take the code from here, the library is here (save it as "SetMenuItemEx.pbi") and a demo code is in the next post:
Code: Select all
;
;**********************************************************************************
;
; SetMenuItemEx.pbi library
; Windows only
; Zapman - March 2025 - 6.2
; Please go to https://www.editions-humanis.com/downloads/PureBasic/ZapmanDowloads_EN.htm
; to get a full commented and updated version or this code.
;
CompilerIf #PB_Compiler_IsMainFile
EnableExplicit
CompilerEndIf
;
;**********************************************************************************
;
;- 1- STRUCTURES GLOBALS AND CONSTANTES DECLARATIONS
;
Global SMI_MenuHeight = GetSystemMetrics_(#SM_CYMENU)
#SMI_MenuBulletSize = 4
;
EnumerationBinary SMI_ShowSelectionMethod
#SMI_SSW_Bullet = 1
#SMI_SSW_Borders
#SMI_SSW_SystemColor
#SMI_SSW_ShadeBackground
EndEnumeration
;
Global SMI_ShowSelectionMethod
If SMI_ShowSelectionMethod = 0
SMI_ShowSelectionMethod = #SMI_SSW_SystemColor
EndIf
;
#SMI_SubItemSearch = -1
;
Structure MENUITEMINFO_Fixed Align #PB_Structure_AlignC
cbSize.l
fMask.l
fType.l
fState.l
wID.l
hSubMenu.i
hbmpChecked.i
hbmpUnchecked.i
dwItemData.i
*dwTypeData
cch.l
hbmpItem.i
EndStructure
;
#MENU_BARITEM = 8
#MENU_POPUPITEM = 14
#MBI_HOT = 2
#MPI_HOT = 2
#MBI_NORMAL = 1
#MPI_NORMAL = 1
#MENU_BARBACKGROUND = 7
#MENU_POPUPBACKGROUND = 9
#MENU_POPUPCHECK = 11
#MC_CHECKMARKNORMAL = 1
#TMT_FILLCOLOR = 3802
#TMT_TEXTCOLOR = 3803
;
#MIM_MENUDATA = 8
#HBMMENU_CALLBACK = -1
;
Structure MENUINFO Align #PB_Structure_AlignC
cbSize.l
fMask.l
dwStyle.l
cyMax.l
hbrBack.i
dwContextHelpID.l
dwMenuData.i
EndStructure
;
Structure MENUBARINFO Align #PB_Structure_AlignC
cbSize.l
rcBar.RECT
hMenu.i
hwndMenu.i
fBarFocused.b
fFocused.b
fUnused.b
Padding_1.b
EndStructure
;
Enumeration MustBeOwnerdrawn
#SMI_NOT_Ownerdrawn
#SMI_Ownerdrawn
EndEnumeration
;
Structure OwnerdrawnMenuItemDataStruct
*MenuItemTextPtr
*MenuItemImgHandle
MenuItemImgNum.i
MustBeOwnerdrawn.i
IsItemOwnerdrawn.i
IsItemSeparator.i
*ParentMenuHandle
MenuItemPos.i
MenuItemID.i
*MenuItemFont
MenuItemBackColor.l
MenuItemTextColor.l
MenuItemState.l
EndStructure
;
Global NewList MenuItemData.OwnerdrawnMenuItemDataStruct()
;
Define SMI_MemMenuNum = -1, SMI_MemMenuHandle = 0
;
;*******************************************************************************
;- 2- GENERAL FUNCTIONS
Procedure LoadMenuFont()
#SPI_GETNONCLIENTMETRICS = $0029
Protected ncm.NONCLIENTMETRICS
ncm\cbSize = SizeOf(NONCLIENTMETRICS)
;
If SystemParametersInfo_(#SPI_GETNONCLIENTMETRICS, ncm\cbSize, @ncm, 0)
Protected FontName$ = PeekS(@ncm\lfMenuFont\lfFaceName)
Protected FontSize = ncm\lfMenuFont\lfHeight / DesktopResolutionY()
ProcedureReturn LoadFont(#PB_Any, FontName$, FontSize)
EndIf
EndProcedure
;
Global DefaultMenuFont = LoadMenuFont()
;
CompilerIf Not(Defined(GetImageFromShell32, #PB_Procedure))
Procedure GetImageFromShell32(IconNum, ImgWidth, ImgHeight)
;
Protected TransparentImage = CreateImage(#PB_Any, ImgWidth, ImgHeight, 32, #PB_Image_Transparent)
Protected hIcon = ExtractIcon_(0, "shell32.dll", IconNum)
;
If IsImage(TransparentImage) And hIcon
Protected Dest_hDC = StartDrawing(ImageOutput(TransparentImage))
If Dest_hDC
DrawingMode(#PB_2DDrawing_AlphaBlend)
Box(0, 0, ImgWidth, ImgHeight, RGBA(0, 0, 0, 0))
DrawIconEx_(Dest_hDC, 0, 0, hIcon, ImgWidth, ImgHeight, 0, #Null, #DI_NORMAL)
StopDrawing()
DeleteDC_(Dest_hDC)
EndIf
EndIf
DestroyIcon_(hIcon)
;
ProcedureReturn TransparentImage
EndProcedure
CompilerEndIf
;
CompilerIf Not(Defined(ResizeImageToIconSize, #PB_Procedure))
Procedure ResizeImageToIconSize(SourceImage)
;
If SourceImage
If IsImage(SourceImage)
SourceImage = ImageID(SourceImage)
EndIf
;
Protected ResizedImage = CreateImage(#PB_Any, GetSystemMetrics_(#SM_CXSMICON), GetSystemMetrics_(#SM_CYSMICON), 32, #PB_Image_Transparent)
If ResizedImage
If StartDrawing(ImageOutput(ResizedImage))
DrawingMode(#PB_2DDrawing_AlphaBlend)
DrawImage(SourceImage, 0, 0, GetSystemMetrics_(#SM_CXSMICON), GetSystemMetrics_(#SM_CYSMICON))
StopDrawing()
ProcedureReturn ResizedImage
EndIf
EndIf
EndIf
ProcedureReturn #Null
EndProcedure
CompilerEndIf
;
CompilerIf Not(Defined(CreateIconFromImage, #PB_Procedure))
Procedure CreateIconFromImage(hBitmap)
;
Protected iconInfo.ICONINFO, bitmap.BITMAP
;
If IsImage(hBitmap)
hBitmap = ImageID(hBitmap)
EndIf
;
If GetObject_(hBitmap, SizeOf(BITMAP), @bitmap)
;
iconInfo\fIcon = #True
iconInfo\xHotspot = 0
iconInfo\yHotspot = 0
iconInfo\hbmMask = CreateBitmap_(bitmap\bmWidth, bitmap\bmHeight, 1, 1, #Null)
iconInfo\hbmColor = hBitmap
Protected hIcon = CreateIconIndirect_(@iconInfo)
;
DeleteObject_(iconInfo\hbmMask)
;
ProcedureReturn hIcon
EndIf
EndProcedure
CompilerEndIf
;
CompilerIf Not(Defined(DrawTransparentRectangle, #PB_Procedure))
Procedure DrawTransparentRectangle(Dest_hDC, *rect.RECT, CoverColor, Opacity)
;
Protected TempRect.Rect, hBrush
Protected Srce_hDC = CreateCompatibleDC_(Dest_hDC)
;
If CoverColor = 0 : CoverColor = 1 : EndIf
;
If Srce_hDC
Protected ImgWidth = *rect\right - *rect\left
Protected ImgHeight = *rect\bottom - *rect\top
Protected hbmTemp = CreateCompatibleBitmap_(Dest_hDC, ImgWidth, ImgHeight)
If hbmTemp
Protected oldBitmap = SelectObject_(Srce_hDC, hbmTemp)
If oldBitmap
Protected blend, *blend.BLENDFUNCTION = @blend
;
If OpenLibrary(0, "Msimg32.dll")
;
TempRect\left = 0 : TempRect\top = 0
TempRect\right = ImgWidth : TempRect\bottom = ImgHeight
hBrush = CreateSolidBrush_(CoverColor)
FillRect_(Srce_hDC, TempRect, hBrush)
DeleteObject_(hBrush)
;
*blend\BlendOp = #AC_SRC_OVER
*blend\BlendFlags = 0
*blend\AlphaFormat = 0
*blend\SourceConstantAlpha = Opacity
CallFunction(0, "AlphaBlend", Dest_hDC, *rect\left, *rect\top, ImgWidth, ImgHeight, Srce_hDC, 0, 0, ImgWidth, ImgHeight, blend)
;
CloseLibrary(0)
EndIf
;
SelectObject_(Srce_hDC, oldBitmap)
EndIf
DeleteObject_(hbmTemp)
EndIf
DeleteDC_(Srce_hDC)
EndIf
EndProcedure
CompilerEndIf
;
CompilerIf Not(Defined(DrawRightPointingTriangle, #PB_Procedure))
Procedure DrawRightPointingTriangle(hDC, *rc.Rect, tSize, FrontColor, BackColor)
;
Protected *points = AllocateMemory(3 * SizeOf(POINT))
Protected vCenter = *rc\top + (*rc\bottom - *rc\top) / 2 - 1
;
PokeL(*points + 0, *rc\left + tSize)
PokeL(*points + 4, vCenter)
;
PokeL(*points + 8, *rc\left)
PokeL(*points + 12, vCenter + tSize)
;
PokeL(*points + 16, *rc\left);
PokeL(*points + 20, vCenter - tSize)
;
Protected hPen = CreatePen_(#PS_SOLID, 1, FrontColor)
Protected hBrush = CreateSolidBrush_(BackColor)
SelectObject_(hDC, hPen)
SelectObject_(hDC, hBrush)
;
Polygon_(hDC, *points, 3)
;
; CleanUp
DeleteObject_(hPen)
DeleteObject_(hBrush)
FreeMemory(*points)
EndProcedure
CompilerEndIf
;
CompilerIf Not(Defined(DrawCheckmark, #PB_Procedure))
Procedure DrawCheckmark(hDC, *rc.Rect, Size, Color)
Protected pt.POINT, hPen
pt\x = *rc\left
pt\y = *rc\top + (*rc\bottom - *rc\top - Size) / 2
hPen = CreatePen_(#PS_SOLID, 2, Color)
SelectObject_(hDC, hPen)
MoveToEx_(hDC, pt\x + Size/5, pt\y + Size * 2 / 5, 0)
LineTo_(hDC, pt\x + Size * 3 / 5, pt\y + Size * 4 / 5)
LineTo_(hDC, pt\x + Size * 7 / 5, pt\y)
DeleteObject_(hPen)
EndProcedure
CompilerEndIf
;
CompilerIf Not(Defined(GetTextWidthInWindowContext, #PB_Procedure))
Procedure GetTextWidthInWindowContext(hWnd, FontID, Text$)
If IsWindow(hWnd) : hWnd = WindowID(hWnd) : EndIf
If IsFont(FontID) : FontID = FontID(FontID) : EndIf
Protected hDC = GetDC_(hWnd), hOldFont, Size.SIZE
If hDC
hOldFont = SelectObject_(hDC, FontID)
GetTextExtentPoint32_(hDC, Text$, Len(Text$), @Size)
SelectObject_(hDC, hOldFont)
ReleaseDC_(hWnd, hDC)
ProcedureReturn Size\cx
EndIf
ProcedureReturn 0
EndProcedure
CompilerEndIf
;
CompilerIf Not(Defined(DwmSetWindowAttribute, #PB_Prototype))
Prototype.i DwmSetWindowAttribute(hWnd.i, dwAttribute.i, pvAttribute.i, cbAttribute.i)
CompilerEndIf
;
CompilerIf Not(Defined(IsDarkModeEnabled, #PB_Procedure))
Procedure IsDarkModeEnabled()
;
Protected key = 0
Protected darkModeEnabled = 0
;
If RegOpenKeyEx_(#HKEY_CURRENT_USER, "Software\Microsoft\Windows\CurrentVersion\Themes\Personalize", 0, #KEY_READ, @key) = #ERROR_SUCCESS
Protected value = 1
Protected valueSize = SizeOf(value)
If RegQueryValueEx_(key, "AppsUseLightTheme", 0, #Null, @value, @valueSize) = #ERROR_SUCCESS
darkModeEnabled = Abs(value - 1) ; 0 = dark, 1 = light
EndIf
RegCloseKey_(key)
EndIf
;
ProcedureReturn darkModeEnabled
EndProcedure
CompilerEndIf
;
CompilerIf Not(Defined(ApplyDarkModeToWindow, #PB_Procedure))
Procedure ApplyDarkModeToWindow(Window = 0)
;
Protected hWnd = WindowID(Window)
;
If hWnd And OSVersion() >= #PB_OS_Windows_10
Protected hDwmapi = OpenLibrary(#PB_Any, "dwmapi.dll")
;
If hDwmapi
Protected DwmSetWindowAttribute_.DwmSetWindowAttribute = GetFunction(hDwmapi, "DwmSetWindowAttribute")
; Enable dark mode if possible
If DwmSetWindowAttribute_
Protected darkModeEnabled = IsDarkModeEnabled()
If darkModeEnabled
#DWMWA_USE_IMMERSIVE_DARK_MODE = 20
DwmSetWindowAttribute_(hWnd, #DWMWA_USE_IMMERSIVE_DARK_MODE, @darkModeEnabled, SizeOf(darkModeEnabled))
SetWindowColor(Window, $202020)
;
; Force the window to repaint:
If IsWindowVisible_(hWnd)
HideWindow(Window, #True)
HideWindow(Window, #False)
EndIf
EndIf
EndIf
;
CloseLibrary(hDwmapi)
EndIf
EndIf
EndProcedure
CompilerEndIf
;
; *****************************************************************************
;
;- 3. SPECIALIZED PROCEDURES OF THE LIBRARY
;
Procedure SMI_GetLastMenuItem(hMenu)
;
; Return the position of the last menu item of hMenu.
;
Protected LastMenuItem = GetMenuItemCount_(hMenu) - 1
;
If LastMenuItem < 0 Or LastMenuItem > 65535
ProcedureReturn -1
EndIf
ProcedureReturn LastMenuItem
EndProcedure
;
Procedure SMI_InitMenuItemInfoData(*MenuItemInfo.MENUITEMINFO_Fixed)
FillMemory(*MenuItemInfo, SizeOf(MENUITEMINFO_Fixed), 0)
*MenuItemInfo\cbSize = SizeOf(MENUITEMINFO_Fixed)
EndProcedure
;
Procedure.s SMI_GetClassicMenuStringFromPosition(hMenu, Position)
;
Protected MenuItemInfo.MENUITEMINFO_Fixed, ItemString$
;
SMI_InitMenuItemInfoData(@MenuItemInfo)
MenuItemInfo\fMask = #MIIM_STRING
MenuItemInfo\dwTypeData = 0
GetMenuItemInfo_(hMenu, Position, #MF_BYPOSITION, @MenuItemInfo)
;
If MenuItemInfo\cch
ItemString$ = Space(MenuItemInfo\cch)
MenuItemInfo\cch + 1 ; Add room for the ending character.
MenuItemInfo\dwTypeData = @ItemString$
GetMenuItemInfo_(hMenu, Position, #MF_BYPOSITION, @MenuItemInfo)
EndIf
ProcedureReturn ItemString$
EndProcedure
;
Procedure SMI_GetMenuItemPos(hMenu, ItemPosOrIdOrSubmenuHandle, ByPosOrIdOrSubMenuHandle, *ItemPos.Integer, RecursiveSearch = #True)
;
Protected LastItem, Counter, hSubMenu, Result
;
If IsMenu(hMenu)
hMenu = MenuID(hMenu)
EndIf
;
If IsMenu_(ItemPosOrIdOrSubmenuHandle)
ByPosOrIdOrSubMenuHandle = #SMI_SubItemSearch
EndIf
;
If ByPosOrIdOrSubMenuHandle = #MF_BYPOSITION
*ItemPos\i = ItemPosOrIdOrSubmenuHandle
ProcedureReturn hMenu
Else
LastItem = SMI_GetLastMenuItem(hMenu)
For Counter = 0 To LastItem
hSubMenu = GetSubMenu_(hMenu, Counter)
If hSubMenu = 0 And ByPosOrIdOrSubMenuHandle = #MF_BYCOMMAND And GetMenuItemID_(hMenu, Counter) = ItemPosOrIdOrSubmenuHandle
*ItemPos\i = Counter
ProcedureReturn hMenu
Else
If hSubMenu
If ByPosOrIdOrSubMenuHandle = #SMI_SubItemSearch And hSubMenu = ItemPosOrIdOrSubmenuHandle
*ItemPos\i = Counter
ProcedureReturn hMenu
ElseIf RecursiveSearch
Result = SMI_GetMenuItemPos(hSubMenu, ItemPosOrIdOrSubmenuHandle, ByPosOrIdOrSubMenuHandle, *ItemPos, RecursiveSearch)
If Result
ProcedureReturn Result
EndIf
EndIf
EndIf
EndIf
Next
EndIf
EndProcedure
;
Procedure SMI_FillMenuItemData(hMenu, ItemPosOrIdOrSubmenuHandle, *MyMenuItemData.OwnerdrawnMenuItemDataStruct, ByPosOrIdOrSubMenuHandle = #MF_BYCOMMAND, RecursiveSearch = #True)
;
Protected MenuItemInfo.MENUITEMINFO_Fixed
Protected ItemString$, ItemPos
Protected bitmap.bitmap
;
MenuItemInfo\dwItemData = 0
;
hMenu = SMI_GetMenuItemPos(hMenu, ItemPosOrIdOrSubmenuHandle, ByPosOrIdOrSubMenuHandle, @ItemPos, RecursiveSearch)
;
If hMenu And *MyMenuItemData
SMI_InitMenuItemInfoData(@MenuItemInfo)
MenuItemInfo\fMask = #MIIM_FTYPE
GetMenuItemInfo_(hMenu, ItemPos, #MF_BYPOSITION, @MenuItemInfo)
;
If MenuItemInfo\fType & #MFT_SEPARATOR
*MyMenuItemData\IsItemSeparator = #True
EndIf
;
If MenuItemInfo\fType & #MFT_OWNERDRAW
;
SMI_InitMenuItemInfoData(@MenuItemInfo)
MenuItemInfo\fMask = #MIIM_DATA
GetMenuItemInfo_(hMenu, ItemPos, #MF_BYPOSITION, @MenuItemInfo)
EndIf
;
If MenuItemInfo\dwItemData = 0
*MyMenuItemData\IsItemOwnerdrawn = #SMI_NOT_Ownerdrawn
;
SysFreeString_(*MyMenuItemData\MenuItemTextPtr)
ItemString$ = SMI_GetClassicMenuStringFromPosition(hMenu, ItemPos)
*MyMenuItemData\MenuItemTextPtr = SysAllocString_(ItemString$)
;
SMI_InitMenuItemInfoData(@MenuItemInfo)
MenuItemInfo\fMask = #MIIM_BITMAP | #MIIM_STATE
GetMenuItemInfo_(hMenu, ItemPos, #MF_BYPOSITION, @MenuItemInfo)
; Check if the image is valid:
If GetObject_(MenuItemInfo\hbmpItem, SizeOf(BITMAP), @bitmap)
*MyMenuItemData\MenuItemImgHandle = MenuItemInfo\hbmpItem
EndIf
*MyMenuItemData\MenuItemState = MenuItemInfo\fState
;
Else
If MenuItemInfo\dwItemData <> *MyMenuItemData
CopyStructure(MenuItemInfo\dwItemData, *MyMenuItemData, OwnerdrawnMenuItemDataStruct)
EndIf
EndIf
;
*MyMenuItemData\ParentMenuHandle = hMenu
*MyMenuItemData\MenuItemPos = ItemPos
*MyMenuItemData\MenuItemID = GetMenuItemID_(hMenu, ItemPos)
If GetSubMenu_(hMenu, ItemPos)
*MyMenuItemData\MenuItemID = -1
EndIf
;
EndIf
;
ProcedureReturn hMenu
;
EndProcedure
;
Procedure SMI_SaveMenuWindow(hMenu, WindowID)
Protected MenuInfo.MenuInfo
;
MenuInfo\cbSize = SizeOf(MenuInfo)
MenuInfo\fMask = #MIM_MENUDATA
MenuInfo\dwMenuData = WindowID
SetMenuInfo_(hMenu, @MenuInfo)
EndProcedure
;
Procedure SMI_RetreiveMenuWindow(hMenu)
;
Protected MenuInfo.MenuInfo
;
MenuInfo\cbSize = SizeOf(MenuInfo)
MenuInfo\fMask = #MIM_MENUDATA
GetMenuInfo_(hMenu, @MenuInfo)
;
ProcedureReturn MenuInfo\dwMenuData
EndProcedure
;
Procedure SMI_CheckID(*ItemID.Integer)
Static IDNum = $AFFF
If *ItemID\i > $AFFF
MessageRequester("Error", "ID upper that 45055 ($AFFF) are reserved for dynamic allocation.")
EndIf
If *ItemID\i = #PB_Any Or *ItemID\i > $AFFF
IDNum + 1
*ItemID\i = IDNum
EndIf
ProcedureReturn *ItemID\i
EndProcedure
;
Procedure SMI_RetreiveOrCreateMenuItemDataListElement(hMenu, ItemPosOrIdOrSubmenuHandle, ByPosOrIdOrSubMenuHandle = #MF_BYCOMMAND, *ItemPos.Integer = 0, RecursiveSearch = #True)
;
Protected Found = 0, ItemPos, SearchType$, ErrorDetails$
;
If hMenu = #PB_Default And (ByPosOrIdOrSubMenuHandle = #MF_BYCOMMAND Or IsMenu_(ItemPosOrIdOrSubmenuHandle))
ForEach MenuItemData()
If MenuItemData()\MenuItemID = ItemPosOrIdOrSubmenuHandle Or GetSubMenu_(MenuItemData()\ParentMenuHandle, MenuItemData()\MenuItemPos) = ItemPosOrIdOrSubmenuHandle
hMenu = MenuItemData()\ParentMenuHandle
ItemPos = MenuItemData()\MenuItemPos
Found = 1
Break
EndIf
Next
Else
hMenu = SMI_GetMenuItemPos(hMenu, ItemPosOrIdOrSubmenuHandle, ByPosOrIdOrSubMenuHandle, @ItemPos, RecursiveSearch)
EndIf
If hMenu And hMenu <> #PB_Default
If Found = 0
ForEach MenuItemData()
If MenuItemData()\ParentMenuHandle = hMenu And MenuItemData()\MenuItemPos = ItemPos
Found = 1
Break
EndIf
Next
EndIf
If Found = 0
AddElement(MenuItemData())
MenuItemData()\MenuItemFont = #PB_Default
MenuItemData()\MenuItemBackColor = #PB_Default
MenuItemData()\MenuItemTextColor = #PB_Default
EndIf
;
SMI_FillMenuItemData(hMenu, ItemPos, @MenuItemData(), #MF_BYPOSITION)
;
Else
If ByPosOrIdOrSubMenuHandle = #MF_BYCOMMAND
SearchType$ = "BY COMMAND"
Else
SearchType$ = "BY POSITION" + #CR$ + #CR$ + "You should try to call 'SetMenuItem...()' instead of 'SetMenuTitle...()'."
EndIf
If IsMenu_(ItemPosOrIdOrSubmenuHandle)
ErrorDetails$ = #CR$ + " • " + Str(ItemPosOrIdOrSubmenuHandle) + " is a menu handle."
ElseIf ItemPosOrIdOrSubmenuHandle > 20 And ItemPosOrIdOrSubmenuHandle < $FFFF
ErrorDetails$ = #CR$ + " • " + Str(ItemPosOrIdOrSubmenuHandle) + " seems to be an item ID."
EndIf
MessageRequester("Error", "Unable to retreive the item " + Str(ItemPosOrIdOrSubmenuHandle) + #CR$ + ErrorDetails$ + #CR$ + " • The search was: " + SearchType$)
EndIf
;
If *ItemPos
*ItemPos\i = ItemPos
EndIf
;
ProcedureReturn hMenu
EndProcedure
;
Procedure SMI_HasMenuImage(hMenu)
Protected LastItem, Counter, Result = #False
;
PushListPosition(MenuItemData())
;
LastItem = SMI_GetLastMenuItem(hMenu)
For Counter = 0 To LastItem
SMI_RetreiveOrCreateMenuItemDataListElement(hMenu, Counter, #MF_BYPOSITION, 0, #False)
If MenuItemData()\MenuItemImgHandle
Result = #True
Break
EndIf
Next
;
PopListPosition(MenuItemData())
;
ProcedureReturn Result
;
EndProcedure
;
Procedure SMI_HasMenuSubmenu(hMenu)
Protected LastItem, Counter
;
LastItem = SMI_GetLastMenuItem(hMenu)
For Counter = 0 To LastItem
If GetSubMenu_(hMenu, Counter)
ProcedureReturn #True
EndIf
Next
ProcedureReturn #False
;
EndProcedure
;
Procedure SMI_HasMenuOwnerdrawnItems(hMenu, RecursiveSearch = #False)
;
Protected Counter, hSubMenu, Result
;
If IsMenu(hMenu)
hMenu = MenuID(hMenu)
EndIf
;
PushListPosition(MenuItemData())
;
Protected LastItem = SMI_GetLastMenuItem(hMenu)
For Counter = 0 To LastItem
SMI_RetreiveOrCreateMenuItemDataListElement(hMenu, Counter, #MF_BYPOSITION)
If MenuItemData()\MustBeOwnerdrawn = #SMI_Ownerdrawn
Result = #True
Break
EndIf
;
If RecursiveSearch
hSubMenu = GetSubMenu_(hMenu, Counter)
Protected *CurrentElement = @MenuItemData()
If hSubMenu And SMI_HasMenuOwnerdrawnItems(hSubMenu)
Result = #True
Break
Else
ChangeCurrentElement(MenuItemData(), *CurrentElement)
EndIf
EndIf
Next
;
PopListPosition(MenuItemData())
;
ProcedureReturn Result
EndProcedure
;
Procedure SMI_HasMenuItemChecked(hMenu)
Protected LastItem, Counter, Result = #False
;
PushListPosition(MenuItemData())
;
LastItem = SMI_GetLastMenuItem(hMenu)
For Counter = 0 To LastItem
SMI_RetreiveOrCreateMenuItemDataListElement(hMenu, Counter, #MF_BYPOSITION, 0, #False)
If MenuItemData()\MenuItemState & #MF_CHECKED
Result = #True
Break
EndIf
Next
;
PopListPosition(MenuItemData())
;
ProcedureReturn Result
;
EndProcedure
;
Declare SMI_OwnerDrawnCallback(hWnd, uMsg, wParam, lParam)
;
Procedure SMI_AttachCallbackToWindow(WindowID)
If GetProp_(WindowID, "SMI_OldCallBack") = 0
Protected SMI_OldCallBack = SetWindowLongPtr_(WindowID, #GWL_WNDPROC, @SMI_OwnerDrawnCallback())
SetProp_(WindowID, "SMI_ActualCallBack", @SMI_OwnerDrawnCallback())
SetProp_(WindowID, "SMI_OldCallBack", SMI_OldCallBack)
SetProp_(WindowID, "SMI_MustBeinitialized", 1)
EndIf
EndProcedure
;
Procedure SMI_PrepareItemToBeOwnerDrawn(hMenu = #PB_Default, ItemPos = #PB_Default)
;
Protected MenuItemInfo.MENUITEMINFO_Fixed
Protected LastItem, Counter
;
If hMenu <> #PB_Default And ItemPos <> #PB_Default
SMI_RetreiveOrCreateMenuItemDataListElement(hMenu, ItemPos, #MF_BYPOSITION)
EndIf
;
MenuItemData()\MustBeOwnerdrawn = #SMI_Ownerdrawn
;
If MenuItemData()\IsItemOwnerdrawn <> #SMI_Ownerdrawn And IsWindow(EventWindow())
PushListPosition(MenuItemData())
hMenu = MenuItemData()\ParentMenuHandle
LastItem = SMI_GetLastMenuItem(hMenu)
For Counter = 0 To LastItem
SMI_RetreiveOrCreateMenuItemDataListElement(hMenu, Counter, #MF_BYPOSITION)
;
MenuItemData()\IsItemOwnerdrawn = #SMI_Ownerdrawn
SMI_InitMenuItemInfoData(@MenuItemInfo)
MenuItemInfo\fMask = #MIIM_FTYPE | #MIIM_BITMAP | #MIIM_DATA
MenuItemInfo\fType = #MFT_OWNERDRAW
MenuItemInfo\hbmpItem = #HBMMENU_CALLBACK
If MenuItemData()\IsItemSeparator
MenuItemInfo\fType | #MFT_SEPARATOR
EndIf
If GetSubMenu_(MenuItemData()\ParentMenuHandle, MenuItemData()\MenuItemPos)
MenuItemInfo\fMask | #MIIM_ID
MenuItemInfo\wID = 1
EndIf
MenuItemInfo\dwItemData = @MenuItemData()
SetMenuItemInfo_(MenuItemData()\ParentMenuHandle, MenuItemData()\MenuItemPos, #MF_BYPOSITION, @MenuItemInfo)
;
Next
PopListPosition(MenuItemData())
;
EndIf
;
Protected WindowID = SMI_RetreiveMenuWindow(MenuItemData()\ParentMenuHandle)
If WindowID
SMI_AttachCallbackToWindow(WindowID)
EndIf
;
EndProcedure
;
Declare SMI_FreeMenu(hMenu)
Declare SMI_CloseSubMenu()
;
Procedure SMI_OwnerDrawnCallback(hWnd, uMsg, wParam, lParam)
;
Protected *drawItem.DRAWITEMSTRUCT
Protected *measureItem.MEASUREITEMSTRUCT
Protected hDC, rc.RECT, rc2.RECT, Text$, ImgAddress
Protected BackColor, TextColor, hBrush, ImgVerticalMargin
Protected hMenu, ItemNum, ODTType, ObjectTheme
Protected SelectedFont, BackLuminosity, TextLuminosity
Protected HasMenuImage, HasCheckedItem, Selected, Disabled, Opacity, CoverColor, hTheme
Protected ItemThemePart, ItemHotState, ItemNormalState, ItemBackGround, ApplySelectionEffect
Protected HasSubMenu = 0, ItemPos, menuItemRect.RECT, cont
Protected MenuItemInfo.MENUITEMINFO_Fixed, TWidth
Protected *MyMenuItemData.OwnerdrawnMenuItemDataStruct
Static ItemPosOver = #PB_Default, ItemPosHOTLIGHT = #PB_Default, DisableMainMenu = #WA_ACTIVE
;
If GetProp_(hWnd, "SMI_MustBeinitialized") = 1 And IsWindow(EventWindow()) And WindowID(EventWindow()) = hWnd
;
If GetMenu_(hWnd)
SetProp_(hWnd, "SMI_MustBeinitialized", 2)
SendMessage_(hWnd, #WM_INITMENU, GetMenu_(hWnd), 0)
EndIf
EndIf
;
Select uMsg
;
Case #WM_DESTROY
SMI_FreeMenu(GetMenu_(hWnd))
;
Case #WM_INITMENU, #WM_INITMENUPOPUP
hMenu = wParam
If SMI_HasMenuOwnerdrawnItems(hMenu)
SMI_PrepareItemToBeOwnerDrawn(hMenu, 0)
BackColor = #PB_Default
CompilerIf Defined(SetGadgetsColorsFromTheme, #PB_Procedure)
If ListSize(InterfaceColorPresets()) > 0
BackColor = GetRealColorFromType("BackgroundColor", InterfaceColorPresets()\BackgroundColor)
EndIf
CompilerElseIf Defined(ObjectTheme, #PB_Module)
BackColor = ObjectTheme::GetObjectThemeAttribute(0, #PB_Gadget_BackColor)
CompilerEndIf
If BackColor <> #PB_Default
#MIM_BACKGROUND = $2
#MIM_APPLYTOSUBMENUS = $80000000
Protected menuInfo.MENUINFO
hBrush = CreateSolidBrush_(BackColor)
menuInfo\cbSize = SizeOf(MENUINFO)
menuInfo\hbrBack = hBrush
menuInfo\fMask = #MIM_BACKGROUND ;| #MIM_APPLYTOSUBMENUS
SetMenuInfo_(hMenu, @menuInfo)
EndIf
If hMenu = GetMenu_(hWnd) And GetProp_(hWnd, "SMI_MustBeinitialized")
DrawMenuBar_(hWnd)
EndIf
EndIf
SetProp_(hWnd, "SMI_MustBeinitialized", 0)
;
Case #WM_ACTIVATE
If wParam <> DisableMainMenu
DisableMainMenu = wParam
DrawMenuBar_(hwnd)
EndIf
;
Case #WM_MEASUREITEM
*measureItem = lParam
;
ODTType = *measureItem\CtlType
;
If ODTType = #ODT_MENU
;
*MyMenuItemData = *measureItem\itemData
hMenu = *MyMenuItemData\ParentMenuHandle
;
If hMenu
;
If *MyMenuItemData\IsItemSeparator = #False
Text$ = PeekS(*MyMenuItemData\MenuItemTextPtr)
If IsFont(*MyMenuItemData\MenuItemFont)
TWidth = GetTextWidthInWindowContext(hWnd, *MyMenuItemData\MenuItemFont, Text$)
Else
TWidth = GetTextWidthInWindowContext(hWnd, DefaultMenuFont, Text$)
EndIf
;
If SMI_ShowSelectionMethod & #SMI_SSW_Bullet
TWidth + DesktopScaledX(#SMI_MenuBulletSize)
EndIf
;
If hMenu = GetMenu_(hWnd)
HasMenuImage = *MyMenuItemData\MenuItemImgHandle
If *MyMenuItemData\MenuItemState & #MF_CHECKED
HasCheckedItem = 1
EndIf
TWidth + DesktopScaledX(6)
Else
HasMenuImage = SMI_HasMenuImage(hMenu)
HasSubMenu = SMI_HasMenuSubmenu(hMenu)
HasCheckedItem = SMI_HasMenuItemChecked(hMenu)
TWidth + DesktopScaledX(18)
EndIf
;
If HasMenuImage
; If the menu has an image, the width must be increased to draw the image.
TWidth + GetSystemMetrics_(#SM_CXSMICON) + DesktopScaledX(5)
EndIf
If HasSubMenu : TWidth + DesktopScaledX(25) : EndIf
If HasCheckedItem
TWidth + DesktopScaledX(15)
If SMI_ShowSelectionMethod & #SMI_SSW_Bullet
TWidth + DesktopScaledX(#SMI_MenuBulletSize)
EndIf
EndIf
;
If FindString(Text$, #TAB$)
TWidth + DesktopScaledX(15)
EndIf
*measureItem\itemWidth = TWidth
*measureItem\itemHeight = GetSystemMetrics_(#SM_CYMENU) + 2
Else
*measureItem\itemWidth = DesktopScaledX(10)
*measureItem\itemHeight = DesktopScaledY(8)
EndIf
;
EndIf
;
EndIf
;
Case #WM_DRAWITEM
If lParam
*drawItem = lParam
ItemNum = *drawItem\itemID
ODTType = *drawItem\CtlType
If ODTType = #ODT_MENU
;
hMenu = *drawItem\hwndItem
*MyMenuItemData = *drawItem\itemData
;
ImgVerticalMargin = (GetSystemMetrics_(#SM_CYMENU) - GetSystemMetrics_(#SM_CYSMICON)) / 2
If *drawItem\itemState & #ODS_SELECTED Or *drawItem\itemState & #ODS_HOTLIGHT Or ItemPosHOTLIGHT = *MyMenuItemData\MenuItemPos
If ItemPosHOTLIGHT <> *MyMenuItemData\MenuItemPos
ItemPosHOTLIGHT = #PB_Default
EndIf
Selected = 1
EndIf
If DisableMainMenu = #WA_INACTIVE Or *drawItem\itemState & #ODS_GRAYED
Disabled = 1
Selected = 0
EndIf
;
hDC = *drawItem\hdc
rc = *drawItem\rcItem
hTheme = OpenThemeData_(#Null, @"MENU")
If hTheme
If hMenu = GetMenu_(hWnd)
ItemThemePart = #MENU_BARITEM
ItemBackGround = #MENU_BARBACKGROUND
ItemHotState = #MBI_HOT
ItemNormalState = #MBI_NORMAL
Else
ItemThemePart = #MENU_POPUPITEM
ItemBackGround = #MENU_POPUPBACKGROUND
ItemHotState = #MPI_HOT
ItemNormalState = #MPI_NORMAL
EndIf
EndIf
;
Text$ = PeekS(*MyMenuItemData\MenuItemTextPtr)
ImgAddress = *MyMenuItemData\MenuItemImgHandle
;
If *MyMenuItemData\IsItemSeparator Or Text$ = "" : Disabled = 0 : EndIf
;
If IsFont(*MyMenuItemData\MenuItemFont)
SelectedFont = FontID(*MyMenuItemData\MenuItemFont)
Else
SelectedFont = FontID(DefaultMenuFont)
EndIf
SelectObject_(hDC, SelectedFont)
;
Protected BackGroundMustBePainted = 1
Protected TextMustBePainted = 1
;
BackColor = *MyMenuItemData\MenuItemBackColor
If BackColor = #PB_Default
CompilerIf Defined(SetGadgetsColorsFromTheme, #PB_Procedure)
If ListSize(InterfaceColorPresets()) > 0
BackColor = GetRealColorFromType("BackgroundColor", InterfaceColorPresets()\BackgroundColor)
EndIf
CompilerElseIf Defined(ObjectTheme, #PB_Module)
BackColor = ObjectTheme::GetObjectThemeAttribute(0, #PB_Gadget_BackColor)
CompilerEndIf
If BackColor = #PB_Default
If hTheme
BackGroundMustBePainted = DrawThemeBackground_(hTheme, hDC, ItemBackGround, ItemNormalState, @rc, 0)
If GetThemeColor_(hTheme, ItemThemePart, ItemNormalState, #TMT_FILLCOLOR, @BackColor) <> #S_OK
BackColor = GetPixel_(hDC, (rc\left + rc\right) / 2, (rc\top + rc\bottom) / 2)
EndIf
EndIf
If BackColor = #PB_Default
If hMenu = GetMenu_(hWnd)
BackColor = GetSysColor_(#COLOR_MENUBAR)
Else
BackColor = GetSysColor_(#COLOR_MENU)
EndIf
EndIf
EndIf
EndIf
;
TextColor = *MyMenuItemData\MenuItemTextColor
Protected KeepTextColorDefault = 1
If TextColor = #PB_Default
CompilerIf Defined(SetGadgetsColorsFromTheme, #PB_Procedure)
If ListSize(InterfaceColorPresets()) > 0
TextColor = GetRealColorFromType("TextColor", InterfaceColorPresets()\TextColor)
KeepTextColorDefault = 0
EndIf
CompilerElseIf Defined(ObjectTheme, #PB_Module)
TextColor = ObjectTheme::GetObjectThemeAttribute(#PB_GadgetType_Button, #PB_Gadget_FrontColor)
CompilerEndIf
If TextColor = #PB_Default
TextColor = GetSysColor_(#COLOR_MENUTEXT)
If hTheme
If GetThemeColor_(hTheme, ItemThemePart, ItemNormalState, #TMT_TEXTCOLOR, @TextColor) <> #S_OK
TextColor = GetSysColor_(#COLOR_MENUTEXT)
EndIf
EndIf
EndIf
EndIf
;
TextLuminosity = Red(TextColor)*0.299 + Green(TextColor)*0.587 + Blue(TextColor)*0.114
BackLuminosity = Red(BackColor)*0.299 + Green(BackColor)*0.587 + Blue(BackColor)*0.114
;
If BackGroundMustBePainted <> #S_OK
hBrush = CreateSolidBrush_(BackColor)
FillRect_(hDC, @rc, hBrush)
DeleteObject_(hBrush)
EndIf
;
If Selected And (SMI_ShowSelectionMethod & #SMI_SSW_ShadeBackground)
;
If BackLuminosity > 128
CoverColor = #Black
Opacity = 40
Else
CoverColor = #White
Opacity = 60
EndIf
;
DrawTransparentRectangle(hDC, rc, CoverColor, Opacity)
;
If BackLuminosity < 128
TextColor = #White
Else
TextColor = #Black
EndIf
EndIf
;
If Selected And (SMI_ShowSelectionMethod & #SMI_SSW_Borders)
hBrush = CreateSolidBrush_(GetSysColor_(#COLOR_HIGHLIGHT))
FrameRect_(hDC, @rc, hBrush)
DeleteObject_(hBrush)
EndIf
;
If *MyMenuItemData\IsItemSeparator
If *MyMenuItemData\MenuItemTextColor <> #PB_Default
hBrush = CreateSolidBrush_(*MyMenuItemData\MenuItemTextColor)
Else
If BackLuminosity > 128
hBrush = CreateSolidBrush_($A0A0A0)
Else
hBrush = CreateSolidBrush_($505050)
EndIf
EndIf
CopyMemory(@rc, @rc2, SizeOf(RECT))
rc2\top = (rc2\top + rc2\bottom) / 2
rc2\bottom = rc2\top + 1
rc2\left + DesktopScaledX(7)
rc2\right - DesktopScaledX(7)
FillRect_(hDC, @rc2, hBrush)
DeleteObject_(hBrush)
EndIf
;
If Selected And (SMI_ShowSelectionMethod & #SMI_SSW_SystemColor)
ApplySelectionEffect = 1
If hTheme And (*MyMenuItemData\MenuItemBackColor = #PB_Default Or BackLuminosity > 128)
ApplySelectionEffect = DrawThemeBackground_(hTheme, hDC, ItemThemePart, ItemHotState, @rc,0)
EndIf
If ApplySelectionEffect <> #S_OK
If hMenu = GetMenu_(hWnd)
Opacity = 40
Else
Opacity = 100
EndIf
CoverColor = GetSysColor_(#COLOR_HIGHLIGHT)
If BackLuminosity < 128
Opacity = 150
EndIf
;
DrawTransparentRectangle(hDC, rc, CoverColor, Opacity)
EndIf
EndIf
;
If *MyMenuItemData\MenuItemState & #MF_CHECKED
CopyMemory(@rc, @rc2, SizeOf(RECT))
rc2\left + DesktopScaledX(3)
rc2\right = rc2\left + DesktopScaledX(16)
DrawCheckmark(hDC, @rc2, DesktopScaledX(10), TextColor)
EndIf
;
If *MyMenuItemData\MenuItemState & #MF_CHECKED Or (hMenu <> GetMenu_(hWnd) And SMI_HasMenuItemChecked(hMenu))
rc\left + DesktopScaledX(18)
EndIf
;
If SMI_ShowSelectionMethod & #SMI_SSW_Bullet
rc\Left + DesktopScaledX(5)
If Selected
DrawRightPointingTriangle(hDC, rc, DesktopScaledX( #SMI_MenuBulletSize), TextColor, BackColor)
rc\left + DesktopScaledX(#SMI_MenuBulletSize + 5)
Else
rc\left + DesktopScaledX(#SMI_MenuBulletSize + 5) / 2
EndIf
Else
If hMenu = GetMenu_(hWnd)
rc\Left + DesktopScaledX(8)
Else
rc\Left + DesktopScaledX(6)
EndIf
EndIf
;
If ImgAddress
;
Protected icone = CreateIconFromImage(ImgAddress)
If icone <> 0
DrawIconEx_(hDC, rc\left, rc\top + ImgVerticalMargin, icone, 0, 0, 0, #Null, #DI_NORMAL)
EndIf
;
EndIf
;
If ImgAddress Or (hMenu <> GetMenu_(hWnd) And SMI_HasMenuImage(hMenu))
rc\left + GetSystemMetrics_(#SM_CXSMICON) + DesktopScaledX(5)
EndIf
;
rc\Left + DesktopScaledX(2)
;
Protected PosTab = FindString(Text$, #TAB$)
If PosTab
Protected AfterTab$ = Mid(Text$, PosTab + 1)
Text$ = Left(Text$, PosTab - 1)
rc\right - DesktopScaledX(7)
EndIf
If hTheme And TextColor = #PB_Default And KeepTextColorDefault
TextMustBePainted = DrawThemeText_(hTheme, hDC, ItemThemePart, ItemNormalState, @Text$, Len(Text$),#DT_LEFT | #DT_VCENTER | #DT_SINGLELINE,0,@rc)
If TextMustBePainted = #S_OK And AfterTab$
DrawThemeText_(hTheme, hDC, ItemThemePart, ItemNormalState, @AfterTab$, Len(AfterTab$),#DT_RIGHT | #DT_VCENTER | #DT_SINGLELINE,0,@rc)
EndIf
EndIf
If TextMustBePainted <> #S_OK
SetTextColor_(hDC, TextColor)
SetBkMode_(hDC, #TRANSPARENT)
DrawText_(hDC, Text$, Len(Text$), @rc, #DT_LEFT | #DT_VCENTER | #DT_SINGLELINE)
If AfterTab$
DrawText_(hDC, AfterTab$, Len(AfterTab$), @rc, #DT_RIGHT | #DT_VCENTER | #DT_SINGLELINE)
EndIf
EndIf
;
If Disabled
If BackLuminosity > 128
CoverColor = #White
Else
CoverColor = #Black
EndIf
rc = *drawItem\rcItem
DrawTransparentRectangle(hDC, rc, CoverColor, 128)
EndIf
;
If hTheme
CloseThemeData_(hTheme)
EndIf
;
EndIf
;
EndIf
Case #WM_NCMOUSEMOVE
hMenu = GetMenu_(hwnd)
If hMenu
Protected mbi.MENUBARINFO\cbSize = SizeOf(MENUBARINFO)
GetMenuBarInfo_(hwnd, $FFFFFFFD, 0, @mbi) ; #OBJID_MENU = $FFFFFFFD
If mbi And PtInRect_(@mbi\rcBar, ((lParam & $FFFF0000) << 16) + (lParam & $FFFF))
Cont = 1
If ItemPosOver <> 0 And GetMenuItemRect_(hwnd, hMenu, ItemPosOver, @menuItemRect)
If PtInRect_(@menuItemRect, ((lParam & $FFFF0000) << 16) + (lParam & $FFFF))
Cont = 0
EndIf
EndIf
If Cont
Protected LastMenuItem = SMI_GetLastMenuItem(hMenu)
For ItemPos = 0 To LastMenuItem
If ItemPos <> ItemPosOver
GetMenuItemRect_(hwnd, hMenu, ItemPos, @menuItemRect)
If PtInRect_(@menuItemRect, ((lParam & $FFFF0000) << 16) + (lParam & $FFFF))
ItemPosOver = ItemPos
SMI_InitMenuItemInfoData(@MenuItemInfo.MENUITEMINFO_Fixed)
MenuItemInfo\fMask = #MIIM_FTYPE
GetMenuItemInfo_(hMenu, ItemPos, #MF_BYPOSITION, @MenuItemInfo)
If MenuItemInfo\fType & #MFT_OWNERDRAW
ItemPosHOTLIGHT = ItemPos
DrawMenuBar_(hWnd)
ElseIf ItemPosHOTLIGHT > #PB_Default
ItemPosHOTLIGHT = #PB_Default
DrawMenuBar_(hWnd)
EndIf
EndIf
EndIf
Next
EndIf
Else
ItemPosOver = #PB_Default
If ItemPosHOTLIGHT > #PB_Default
ItemPosHOTLIGHT = #PB_Default
DrawMenuBar_(hWnd)
EndIf
EndIf
EndIf
;
Case #WM_MOUSEMOVE, #WM_NCLBUTTONDOWN
ItemPosOver = #PB_Default
If ItemPosHOTLIGHT > #PB_Default
ItemPosHOTLIGHT = #PB_Default
DrawMenuBar_(hWnd)
EndIf
EndSelect
;
Protected SMI_OldCallBack = GetProp_(hWnd, "SMI_OldCallBack")
ProcedureReturn CallWindowProc_(SMI_OldCallBack, hWnd, uMsg, wParam, lParam)
EndProcedure
;
Procedure SMI_RedrawMenuIfMainMenu(hMenu)
;
If IsMenu(hMenu)
hMenu = MenuID(hMenu)
EndIf
If IsWindow(EventWindow()) And GetMenu_(WindowID(EventWindow())) = hMenu
DrawMenuBar_(WindowID(EventWindow()))
ProcedureReturn #True
EndIf
EndProcedure
;
Procedure SMI_ResizeMenu(hMenu, RecursiveSearch = #False)
;
Protected MenuItemInfo.MENUITEMINFO_Fixed
Protected ItemPos, LastMenuItem, Counter, hSubMenu
;
If IsMenu(hMenu)
hMenu = MenuID(hMenu)
EndIf
;
If hMenu
If IsWindow(EventWindow())
LastMenuItem = SMI_GetLastMenuItem(hMenu)
For Counter = 0 To LastMenuItem
If SMI_HasMenuOwnerdrawnItems(hMenu)
SMI_InitMenuItemInfoData(@MenuItemInfo)
MenuItemInfo\fMask = #MIIM_BITMAP
MenuItemInfo\hbmpItem = #HBMMENU_CALLBACK
SetMenuItemInfo_(hMenu, Counter, #MF_BYPOSITION, @MenuItemInfo)
EndIf
hSubMenu = GetSubMenu_(hMenu, Counter)
If RecursiveSearch And hSubMenu
SMI_ResizeMenu(hSubMenu, RecursiveSearch)
EndIf
Next
If GetMenu_(WindowID(EventWindow())) = hMenu
DrawMenuBar_(WindowID(EventWindow()))
EndIf
ProcedureReturn #True
EndIf
EndIf
EndProcedure
;
; *****************************************************************************
;
;- 4. LIBRARY NEW FUNCTIONS
;
Procedure ApplyThemesToMenu(hMenu, RecursiveSearch = #True)
;
;
Protected ItemPos, LastMenuItem, Counter, hSubMenu
;
If IsMenu(hMenu)
hMenu = MenuID(hMenu)
EndIf
;
If hMenu
LastMenuItem = SMI_GetLastMenuItem(hMenu)
For Counter = 0 To LastMenuItem
SMI_PrepareItemToBeOwnerDrawn(hMenu, Counter)
hSubMenu = GetSubMenu_(hMenu, Counter)
If RecursiveSearch And hSubMenu
ApplyThemesToMenu(hSubMenu, RecursiveSearch)
EndIf
Next
If IsWindow(EventWindow()) And GetMenu_(WindowID(EventWindow())) = hMenu
DrawMenuBar_(WindowID(EventWindow()))
EndIf
ProcedureReturn #True
EndIf
EndProcedure
;
Procedure SetMenuItemImage(hMenu, ItemPosOrIdOrSubmenuHandle, *ItemImagePtr, ByPosOrIdOrSubMenuHandle = #MF_BYCOMMAND)
;
Protected MenuItemInfo.MENUITEMINFO_Fixed
Protected ItemPos, Result
;
If *ItemImagePtr <> #PB_Default
PushListPosition(MenuItemData())
;
hMenu = SMI_RetreiveOrCreateMenuItemDataListElement(hMenu, ItemPosOrIdOrSubmenuHandle, ByPosOrIdOrSubMenuHandle, @ItemPos)
;
If IsImage(*ItemImagePtr)
*ItemImagePtr = ImageID(*ItemImagePtr)
EndIf
;
If hMenu
;
If IsImage(MenuItemData()\MenuItemImgNum)
FreeImage(MenuItemData()\MenuItemImgNum)
EndIf
MenuItemData()\MenuItemImgHandle = 0
;
If *ItemImagePtr
MenuItemData()\MenuItemImgNum = ResizeImageToIconSize(*ItemImagePtr)
If MenuItemData()\MenuItemImgNum
MenuItemData()\MenuItemImgHandle = ImageID(MenuItemData()\MenuItemImgNum)
EndIf
EndIf
;
If MenuItemData()\IsItemOwnerdrawn = #SMI_NOT_Ownerdrawn
SMI_InitMenuItemInfoData(@MenuItemInfo)
MenuItemInfo\fMask = #MIIM_BITMAP
MenuItemInfo\hbmpItem = MenuItemData()\MenuItemImgHandle
SetMenuItemInfo_(hMenu, ItemPos, #MF_BYPOSITION, @MenuItemInfo)
;
ElseIf MenuItemData()\MustBeOwnerdrawn = #SMI_Ownerdrawn
SMI_ResizeMenu(hMenu)
EndIf
;
Result = #True
EndIf
;
PopListPosition(MenuItemData())
EndIf
;
ProcedureReturn Result
EndProcedure
;
Procedure SetMenuTitleImage(hMenu, ItemPos, *ItemImagePtr)
ProcedureReturn SetMenuItemImage(hMenu, ItemPos, *ItemImagePtr, #MF_BYPOSITION)
EndProcedure
;
Procedure GetMenuItemImage(hMenu, ItemPosOrIdOrSubmenuHandle, ByPosOrIdOrSubMenuHandle = #MF_BYCOMMAND)
PushListPosition(MenuItemData())
;
If SMI_RetreiveOrCreateMenuItemDataListElement(hMenu, ItemPosOrIdOrSubmenuHandle, ByPosOrIdOrSubMenuHandle)
Protected Result = MenuItemData()\MenuItemImgHandle
EndIf
;
PopListPosition(MenuItemData())
ProcedureReturn Result
EndProcedure
;
Procedure GetMenuTitleImage(hMenu, ItemPos)
ProcedureReturn GetMenuItemImage(hMenu, ItemPos, #MF_BYPOSITION)
EndProcedure
;
Procedure SetMenuItemColor(hMenu, ItemPosOrIdOrSubmenuHandle, ColorType, ItemColor, ByPosOrIdOrSubMenuHandle = #MF_BYCOMMAND)
;
Protected ItemPos, Result
;
PushListPosition(MenuItemData())
;
hMenu = SMI_RetreiveOrCreateMenuItemDataListElement(hMenu, ItemPosOrIdOrSubmenuHandle, ByPosOrIdOrSubMenuHandle, @ItemPos)
;
If hMenu
;
SMI_PrepareItemToBeOwnerDrawn()
;
If ColorType = #PB_Gadget_FrontColor
MenuItemData()\MenuItemTextColor = ItemColor
Else
MenuItemData()\MenuItemBackColor = ItemColor
EndIf
;
SMI_RedrawMenuIfMainMenu(hMenu)
;
Result = #True
EndIf
;
PopListPosition(MenuItemData())
ProcedureReturn Result
EndProcedure
;
Procedure SetMenuTitleColor(hMenu, ItemPos, ColorType, ItemColor)
ProcedureReturn SetMenuItemColor(hMenu, ItemPos, ColorType, ItemColor, #MF_BYPOSITION)
EndProcedure
;
Procedure GetMenuItemColor(hMenu, ItemPosOrIdOrSubmenuHandle, ColorType, ByPosOrIdOrSubMenuHandle = #MF_BYCOMMAND)
PushListPosition(MenuItemData())
;
If SMI_RetreiveOrCreateMenuItemDataListElement(hMenu, ItemPosOrIdOrSubmenuHandle, ByPosOrIdOrSubMenuHandle)
If ColorType = #PB_Gadget_FrontColor
Protected Result = MenuItemData()\MenuItemTextColor
Else
Result = MenuItemData()\MenuItemBackColor
EndIf
EndIf
;
PopListPosition(MenuItemData())
ProcedureReturn Result
EndProcedure
;
Procedure GetMenuTitleColor(hMenu, ItemPos, ColorType)
ProcedureReturn GetMenuItemColor(hMenu, ItemPos, ColorType, #MF_BYPOSITION)
EndProcedure
;
Procedure SetMenuColor(hMenu, ColorType, ItemColor, RecursiveSearch = #True)
;
Protected LastItem, Counter, hSubMenu
If IsMenu(hMenu)
hMenu = MenuID(hMenu)
EndIf
LastItem = SMI_GetLastMenuItem(hMenu)
For Counter = 0 To LastItem
SetMenuItemColor(hMenu, Counter, ColorType, ItemColor, #MF_BYPOSITION)
hSubMenu = GetSubMenu_(hMenu, Counter)
If RecursiveSearch And hSubMenu
SetMenuColor(hSubMenu, ColorType, ItemColor, #True)
EndIf
Next
If IsWindow(EventWindow())
SetProp_(WindowID(EventWindow()), "SMI_MustBeinitialized", 1)
EndIf
EndProcedure
;
Procedure SetMenuItemFont(hMenu, ItemPosOrIdOrSubmenuHandle, Font, ByPosOrIdOrSubMenuHandle = #MF_BYCOMMAND)
;
Protected ItemPos, Result
;
PushListPosition(MenuItemData())
;
hMenu = SMI_RetreiveOrCreateMenuItemDataListElement(hMenu, ItemPosOrIdOrSubmenuHandle, ByPosOrIdOrSubMenuHandle, @ItemPos)
;
If hMenu
;
SMI_PrepareItemToBeOwnerDrawn()
;
MenuItemData()\MenuItemFont = Font
;
SMI_ResizeMenu(hMenu)
;
Result = #True
EndIf
;
PopListPosition(MenuItemData())
ProcedureReturn Result
EndProcedure
;
Procedure SetMenuTitleFont(hMenu, ItemPosOrIdOrSubmenuHandle, Font)
ProcedureReturn SetMenuItemFont(hMenu, ItemPosOrIdOrSubmenuHandle, Font, #MF_BYPOSITION)
EndProcedure
;
Procedure GetMenuItemFont(hMenu, ItemPosOrIdOrSubmenuHandle, ByPosOrIdOrSubMenuHandle = #MF_BYCOMMAND)
PushListPosition(MenuItemData())
;
If SMI_RetreiveOrCreateMenuItemDataListElement(hMenu, ItemPosOrIdOrSubmenuHandle, ByPosOrIdOrSubMenuHandle)
Protected Result = MenuItemData()\MenuItemFont
EndIf
;
PopListPosition(MenuItemData())
ProcedureReturn Result
EndProcedure
;
Procedure GetMenuTitleFont(hMenu, ItemPosOrIdOrSubmenuHandle)
ProcedureReturn GetMenuItemFont(hMenu, ItemPosOrIdOrSubmenuHandle, #MF_BYPOSITION)
EndProcedure
;
Procedure SetMenuFont(hMenu, Font, RecursiveSearch = #True)
;
Protected LastItem, Counter, hSubMenu
If IsMenu(hMenu)
hMenu = MenuID(hMenu)
EndIf
LastItem = SMI_GetLastMenuItem(hMenu)
For Counter = 0 To LastItem
SetMenuItemFont(hMenu, Counter, Font, #MF_BYPOSITION)
hSubMenu = GetSubMenu_(hMenu, Counter)
If RecursiveSearch And hSubMenu
SetMenuColor(hSubMenu, Font, #True)
EndIf
Next
If IsWindow(EventWindow())
SetProp_(WindowID(EventWindow()), "SMI_MustBeinitialized", 1)
EndIf
EndProcedure
;
Procedure CheckMenuItem(hMenu, ItemPosOrIdOrSubmenuHandle, State = #True, Style = #PB_Default, ByPosOrIdOrSubMenuHandle = #MF_BYCOMMAND)
;
Protected MenuItemInfo.MENUITEMINFO_Fixed
Protected ItemPos, Result
;
PushListPosition(MenuItemData())
;
hMenu = SMI_RetreiveOrCreateMenuItemDataListElement(hMenu, ItemPosOrIdOrSubmenuHandle, ByPosOrIdOrSubMenuHandle, @ItemPos)
;
If hMenu
;
If State
MenuItemData()\MenuItemState | #MF_CHECKED
CheckMenuItem_(hMenu, ItemPos, #MF_BYPOSITION | #MF_CHECKED)
Else
MenuItemData()\MenuItemState & ~#MF_CHECKED
CheckMenuItem_(hMenu, ItemPos, #MF_BYPOSITION | #MF_UNCHECKED)
EndIf
;
SMI_ResizeMenu(hMenu)
;
Result = #True
EndIf
;
PopListPosition(MenuItemData())
ProcedureReturn Result
EndProcedure
;
Procedure IsMenuItemChecked(hMenu, ItemPosOrIdOrSubmenuHandle, ByPosOrIdOrSubMenuHandle = #MF_BYCOMMAND)
PushListPosition(MenuItemData())
;
If SMI_RetreiveOrCreateMenuItemDataListElement(hMenu, ItemPosOrIdOrSubmenuHandle, ByPosOrIdOrSubMenuHandle)
If MenuItemData()\MenuItemState & #MF_CHECKED
Protected Result = #True
EndIf
EndIf
;
PopListPosition(MenuItemData())
ProcedureReturn Result
EndProcedure
;
;
; *****************************************************************************
;
;- 5. FUNCTIONS THAT WILL OVERRIDE PUREBASIC NATIVE FUNCTIONS
Procedure.s SMI_GetMenuItemText(hMenu, ItemPosOrIdOrSubmenuHandle, ByPosOrIdOrSubMenuHandle = #MF_BYCOMMAND)
PushListPosition(MenuItemData())
;
If SMI_RetreiveOrCreateMenuItemDataListElement(hMenu, ItemPosOrIdOrSubmenuHandle, ByPosOrIdOrSubMenuHandle)
Protected Result$ = PeekS(MenuItemData()\MenuItemTextPtr)
EndIf
;
PopListPosition(MenuItemData())
ProcedureReturn Result$
EndProcedure
Procedure.s SMI_GetMenuTitleText(hMenu, ItemPos)
ProcedureReturn SMI_GetMenuItemText(hMenu, ItemPos, #MF_BYPOSITION)
EndProcedure
;
Procedure SMI_SetMenuItemText(hMenu, ItemPosOrIdOrSubmenuHandle, ItemText$, ByPosOrIdOrSubMenuHandle = #MF_BYCOMMAND)
;
Protected MenuItemInfo.MENUITEMINFO_Fixed
Protected ItemPos, Result
;
PushListPosition(MenuItemData())
;
hMenu = SMI_RetreiveOrCreateMenuItemDataListElement(hMenu, ItemPosOrIdOrSubmenuHandle, ByPosOrIdOrSubMenuHandle, @ItemPos)
;
If hMenu
;
SysFreeString_(MenuItemData()\MenuItemTextPtr)
MenuItemData()\MenuItemTextPtr = SysAllocString_(ItemText$)
;
If MenuItemData()\IsItemOwnerdrawn = #SMI_NOT_Ownerdrawn
SMI_InitMenuItemInfoData(@MenuItemInfo)
MenuItemInfo\fMask = #MIIM_STRING
MenuItemInfo\dwTypeData = @ItemText$
SetMenuItemInfo_(hMenu, ItemPos, #MF_BYPOSITION, @MenuItemInfo)
;
ElseIf MenuItemData()\MustBeOwnerdrawn = #SMI_Ownerdrawn
SMI_ResizeMenu(hMenu)
EndIf
;
Result = #True
EndIf
;
PopListPosition(MenuItemData())
ProcedureReturn Result
EndProcedure
;
Procedure SMI_SetMenuTitleText(hMenu, ItemPos, ItemText$)
ProcedureReturn SMI_SetMenuItemText(hMenu, ItemPos, ItemText$, #MF_BYPOSITION)
EndProcedure
;
Procedure SMI_CloseSubMenu()
;
Shared SMI_MemMenuNum, SMI_MemMenuHandle
Protected hMenu, ItemPos
;
If IsMenu(SMI_MemMenuNum) And SMI_MemMenuHandle And MenuID(SMI_MemMenuNum) <> SMI_MemMenuHandle
hMenu = SMI_GetMenuItemPos(SMI_MemMenuNum, SMI_MemMenuHandle, #MF_BYCOMMAND, @ItemPos)
If hMenu
CloseSubMenu()
SMI_MemMenuHandle = hMenu
EndIf
ProcedureReturn #True
Else
If IsMenu(SMI_MemMenuNum)
SMI_MemMenuHandle = MenuID(SMI_MemMenuNum)
EndIf
EndIf
;
EndProcedure
;
Procedure SMI_OpenSubMenu(ItemText$, ItemImage)
;
Shared SMI_MemMenuHandle
;
Protected Result = OpenSubMenu(ItemText$)
If ItemImage <> #PB_Default
SetMenuItemImage(SMI_MemMenuHandle, Result, ItemImage)
Else
SMI_RetreiveOrCreateMenuItemDataListElement(SMI_MemMenuHandle, Result)
EndIf
;
If SMI_HasMenuOwnerdrawnItems(SMI_MemMenuHandle)
SMI_PrepareItemToBeOwnerDrawn(SMI_MemMenuHandle, SMI_GetLastMenuItem(SMI_MemMenuHandle))
EndIf
;
SMI_MemMenuHandle = Result
;
ProcedureReturn Result
EndProcedure
;
Procedure SMI_MenuTitle(ItemText$, ItemImage)
;
Shared SMI_MemMenuNum, SMI_MemMenuHandle
;
While SMI_CloseSubMenu() : Wend
ProcedureReturn SMI_OpenSubMenu(ItemText$, ItemImage)
EndProcedure
;
Procedure SMI_CreateMenu(MenuNum, WindowID)
;
Shared SMI_MemMenuNum, SMI_MemMenuHandle
Protected Result
;
While SMI_CloseSubMenu() : Wend
;
If MenuNum = #PB_Any
Result = CreateMenu(#PB_Any, WindowID)
MenuNum = Result
Else
Result = CreateMenu(MenuNum, WindowID)
EndIf
;
SMI_MemMenuNum = MenuNum
SMI_MemMenuHandle = MenuID(MenuNum)
SMI_SaveMenuWindow(SMI_MemMenuHandle, WindowID)
;
ProcedureReturn Result
EndProcedure
;
Procedure SMI_CreatePopUpMenu(MenuNum)
;
Shared SMI_MemMenuNum, SMI_MemMenuHandle
Protected Result
;
While SMI_CloseSubMenu() : Wend
;
If MenuNum = #PB_Any
Result = CreatePopupMenu(#PB_Any)
MenuNum = Result
Else
Result = CreatePopupMenu(MenuNum)
EndIf
;
SMI_MemMenuNum = MenuNum
SMI_MemMenuHandle = MenuID(MenuNum)
;
ProcedureReturn Result
EndProcedure
;
Procedure SMI_MenuItem(ItemID, ItemText$, ItemImage)
;
Shared SMI_MemMenuHandle
;
SMI_CheckID(@ItemID)
;
MenuItem(ItemID, ItemText$)
;
If ItemImage <> #PB_Default
SetMenuItemImage(SMI_MemMenuHandle, ItemID, ItemImage)
Else
SMI_RetreiveOrCreateMenuItemDataListElement(SMI_MemMenuHandle, ItemID)
EndIf
;
If SMI_HasMenuOwnerdrawnItems(SMI_MemMenuHandle)
SMI_PrepareItemToBeOwnerDrawn(SMI_MemMenuHandle, SMI_GetLastMenuItem(SMI_MemMenuHandle))
EndIf
ProcedureReturn ItemID
EndProcedure
;
Procedure SMI_MenuBar(ItemID)
;
Shared SMI_MemMenuHandle
Protected MenuItemInfo.MENUITEMINFO_Fixed, ItemPos
;
MenuBar()
;
ItemPos = SMI_GetLastMenuItem(SMI_MemMenuHandle)
;
SMI_CheckID(@ItemID)
;
SMI_InitMenuItemInfoData(@MenuItemInfo)
MenuItemInfo\fMask = #MIIM_ID
MenuItemInfo\wID = ItemID
SetMenuItemInfo_(SMI_MemMenuHandle, ItemPos, #MF_BYPOSITION, @MenuItemInfo)
;
If SMI_HasMenuOwnerdrawnItems(SMI_MemMenuHandle)
SMI_PrepareItemToBeOwnerDrawn(SMI_MemMenuHandle, ItemPos)
EndIf
ProcedureReturn ItemID
EndProcedure
;
Procedure SMI_FreeMenu(hMenu)
;
Shared SMI_MemMenuNum, SMI_MemMenuHandle
;
While SMI_CloseSubMenu() : Wend
;
If IsMenu(hMenu)
Protected MenuNum = hMenu
hMenu = MenuID(hMenu)
Else
MenuNum = #PB_Default
EndIf
;
ForEach MenuItemData()
If MenuItemData()\ParentMenuHandle = hMenu
If IsImage(MenuItemData()\MenuItemImgNum)
FreeImage(MenuItemData()\MenuItemImgNum)
EndIf
SysFreeString_(MenuItemData()\MenuItemTextPtr)
Protected hSubMenu = GetSubMenu_(hMenu, MenuItemData()\MenuItemPos)
If hSubMenu
Protected *CurrentElement = @MenuItemData()
SMI_FreeMenu(hSubMenu)
ChangeCurrentElement(MenuItemData(), *CurrentElement)
EndIf
DeleteElement(MenuItemData())
EndIf
Next
If MenuNum <> #PB_Default
FreeMenu(MenuNum)
EndIf
;
EndProcedure
;
Procedure SMI_DisplayPopupMenu(MenuNum, WindowID, X, Y)
;
SMI_SaveMenuWindow(MenuID(MenuNum), WindowID)
;
If SMI_HasMenuOwnerdrawnItems(MenuNum, #True)
SMI_AttachCallbackToWindow(WindowID)
EndIf
;
If X = #PB_Ignore Or Y = #PB_Ignore
ProcedureReturn DisplayPopupMenu(MenuNum, WindowID)
Else
ProcedureReturn DisplayPopupMenu(MenuNum, WindowID, X, Y)
EndIf
EndProcedure
;
;
; *****************************************************************************
;
;- 6. OVERRIDE PUREBASIC NATIVE FUNCTIONS
Macro GetMenuItemText(MenuNum, MenuPos)
SMI_GetMenuItemText(MenuNum, MenuPos)
EndMacro
Macro SetMenuItemText(MenuNum, MenuPos, MenuItemText)
SMI_SetMenuItemText(MenuNum, MenuPos, MenuItemText)
EndMacro
Macro GetMenuTitleText(MenuNum, MenuPos)
SMI_GetMenuTitleText(MenuNum, MenuPos)
EndMacro
Macro SetMenuTitleText(MenuNum, MenuPos, MenuItemText)
SMI_SetMenuTitleText(MenuNum, MenuPos, MenuItemText)
EndMacro
Macro OpenSubMenu(MenuNum, MenuItemImage = #PB_Default)
SMI_OpenSubMenu(MenuNum, MenuItemImage)
EndMacro
Macro CloseSubMenu()
SMI_CloseSubMenu()
EndMacro
Macro MenuTitle(MenuNum, MenuItemImage = #PB_Default)
SMI_MenuTitle(MenuNum, MenuItemImage)
EndMacro
Macro MenuItem(MenuItemID, MenuItemText, MenuItemImage = #PB_Default)
SMI_MenuItem(MenuItemID, MenuItemText, MenuItemImage)
EndMacro
Macro MenuBar(MenuItemID = #PB_Any)
SMI_MenuBar(MenuItemID)
EndMacro
Macro CreateMenu(MenuNum, WindowID)
SMI_CreateMenu(MenuNum, WindowID)
EndMacro
Macro CreateImageMenu(MenuNum, WindowID, Options = 0)
SMI_CreateMenu(MenuNum, WindowID)
EndMacro
Macro CreatePopupMenu(MenuNum)
SMI_CreatePopupMenu(MenuNum)
EndMacro
Macro CreatePopupImageMenu(MenuNum, Options = 0)
SMI_CreatePopupMenu(MenuNum)
EndMacro
Macro FreeMenu(MenuNum)
SMI_FreeMenu(MenuNum)
EndMacro
Macro DisplayPopupMenu(MenuNum, WindowID, X = #PB_Ignore, Y = #PB_Ignore)
SMI_DisplayPopupMenu(MenuNum, WindowID, X, Y)
EndMacro