Page 1 of 1

Icons in menu on XP

Posted: Sat Apr 21, 2007 5:34 am
by Joakim Christiansen
Okay, so I created some beautiful icons and inserted them in my menu using:

Code: Select all

SetMenuItemBitmaps_()
They had a alpha channel too and it worked fine in Windows Vista, but then I tried in Windows XP and of course something had to mess up... :roll:
The icons transparent background turned black and the icons was cut of at 12x12 when they was originally 16x16. I see that the PB editor has 16x16 icons in it's menu and I wonder about how they made this possible? I also wonder about if it's possible to make Windows XP support the transparent background at all or any alpha channel information in the menu icons?
Thanks for any answer! :)

Posted: Sat Apr 21, 2007 11:05 am
by Trond
Those menus are owner-drawn.

Include file:

Code: Select all



Procedure MenuItemEx(MenuItemID, Text.s, Icon.l)
  MenuItem(MenuItemID, Text)
  If Icon
    Icon = Icon ;CatchImage(#PB_Any, Icon)
  EndIf
  ModifyMenu_(MenuID(0), MenuItemID, #MF_OWNERDRAW, MenuItemID, Icon)
EndProcedure

Procedure MenuItemFix(MenuItemID)
  ModifyMenu_(MenuID(0), MenuItemID, #MF_OWNERDRAW, MenuItemID, 0)
EndProcedure

Procedure MeasureMenuItem(WindowID, Message, wParam, lParam)
  Protected ItemHeight.l = 20
  Protected *MeasureItem.MEASUREITEMSTRUCT = lParam
  Protected Text.s
  Protected Img.l
  Protected hDC.l
  Protected Rect.RECT
  Protected TextWidth.l
  Protected Metrics.NONCLIENTMETRICS
  Protected MenuFont.l
  If *MeasureItem\CtlType = #ODT_MENU
    Text = Space(8192)
    GetMenuString_(MenuID(0), *MeasureItem\itemID, @Text, 8192, 0)
    
    Img = CreateImage(-1, 1, 1)
    hDC = StartDrawing(ImageOutput(Img))
      Metrics\cbSize = SizeOf(NONCLIENTMETRICS)
      SystemParametersInfo_(#SPI_GETNONCLIENTMETRICS, SizeOf(NONCLIENTMETRICS), @Metrics, 0)
      MenuFont = CreateFontIndirect_(@Metrics\lfMenuFont)
      SelectObject_(hDC, MenuFont)
      SetTextAlign_(hDC,#TA_LEFT|#TA_TOP|#TA_NOUPDATECP) 
      Rect.RECT\Right = 0
      Rect\Bottom = 0
      DrawText_(hDC, Text, Len(Text), @Rect, #DT_CALCRECT | #DT_EXPANDTABS | #DT_NOCLIP	| #DT_SINGLELINE)
      *MeasureItem\itemWidth = ItemHeight + Rect\Right ;TextWidth(ReplaceString(Text, #TAB$, Space(8)))
    StopDrawing()
    
    With *MeasureItem
      If \itemWidth < 100
        \itemWidth = 100
      EndIf
    EndWith
    
    FreeImage(Img)
    DeleteObject_(MenuFont)
    *MeasureItem\itemHeight = ItemHeight
  EndIf
EndProcedure

Procedure DrawMenuItem(WindowID, Message, wParam, lParam)
  Protected ItemHeight.l = 20
  Protected ItemWidth.l = 24
  Protected *DrawItem.DRAWITEMSTRUCT = lParam
  Protected Item.MENUITEMINFO
  Protected Glyph.l = *DrawItem\itemData
  Protected Text.s = Space(8192)
  Protected hDC
  Protected Left, Top, Right, Bottom
  Protected Brush1, Pen1
  Protected DrawFlag
  GetMenuString_(MenuID(0), *DrawItem\itemID, @Text.s, 8192, 0)
  If *DrawItem\CtlType = #ODT_MENU
    hDC = *DrawItem\hDC
    Left   = *DrawItem\rcItem\left
    Top    = *DrawItem\rcItem\top
    Right  = *DrawItem\rcItem\right
    Bottom = *DrawItem\rcItem\bottom
    If (#ODS_SELECTED & *DrawItem\itemState)
      If (#ODS_GRAYED & *DrawItem\itemState)
        Brush1 = CreateSolidBrush_(GetSysColor_(#COLOR_MENU))
        SetTextColor_(hDC, GetSysColor_(#COLOR_GRAYTEXT))
        Pen1   = CreateSolidBrush_(GetSysColor_(#COLOR_MENU))
      Else
        Brush1 = CreateSolidBrush_(GetSysColor_(#COLOR_HIGHLIGHT))
        SetTextColor_(hDC, GetSysColor_(#COLOR_HIGHLIGHTTEXT))
        Pen1   = CreatePen_(#PS_SOLID, 1, GetSysColor_(#COLOR_HIGHLIGHT))
      EndIf
    ElseIf (#ODS_GRAYED & *DrawItem\itemState)
      Brush1 = CreateSolidBrush_(GetSysColor_(#COLOR_MENU))
      SetTextColor_(hDC, GetSysColor_(#COLOR_GRAYTEXT))
      Pen1   = CreatePen_(#PS_SOLID, 1, GetSysColor_(#COLOR_MENU))
    Else
      Brush1 = CreateSolidBrush_(GetSysColor_(#COLOR_MENU))
      SetTextColor_(hDC, GetSysColor_(#COLOR_MENUTEXT))
      Pen1   = CreatePen_(#PS_SOLID, 1, GetSysColor_(#COLOR_MENU))
    EndIf
    SelectObject_(hDC, Brush1)
    SelectObject_(hDC, Pen1)
    Rectangle_(hDC, Left, Top, Right, Bottom)
    SetBkMode_(hDC, #TRANSPARENT)
    *DrawItem\rcItem\left + ItemWidth + 3
    SystemParametersInfo_(#SPI_GETKEYBOARDCUES, 0, @DrawFlag, 0)
    If (Not DrawFlag) And ((*DrawItem\itemState | #ODS_NOACCEL) = *DrawItem\itemState)
      DrawFlag = #DT_HIDEPREFIX
    Else
      DrawFlag = 0
    EndIf
    DrawFlag = DrawFlag | #DT_SINGLELINE | #DT_VCENTER | #DT_EXPANDTABS
    DrawText_(hDC, Text, Len(Text), *DrawItem\rcItem, DrawFlag)
    *DrawItem\rcItem\left - ItemHeight
    If Glyph
      ;hDCGlyph = StartDrawing(ImageOutput(Glyph))
      ;BitBlt_(hDC, (ItemHeight-ImageHeight(Glyph))/2, (ItemHeight-ImageHeight(Glyph))/2 + Top, ImageWidth(Glyph), ImageHeight(Glyph), hDCGlyph, 0, 0, #SRCCOPY)
      ;StopDrawing()
      DrawIconEx_(hDC, (ItemWidth-ImageWidth(Glyph))/2, (ItemHeight-ImageHeight(Glyph))/2 + Top, ImageID(Glyph), ImageWidth(Glyph), ImageHeight(Glyph), 0, 0, #DI_NORMAL | #DI_COMPAT)
    EndIf
    DeleteObject_(Pen1)
    DeleteObject_(Brush1)
  EndIf
EndProcedure

Example:

Code: Select all


XIncludeFile "super_menu_system.pbi"

Procedure MainWindowCallback(WindowID, Message, wParam, lParam)
  Protected Result = #PB_ProcessPureBasicEvents
    Select Message
      Case #WM_MEASUREITEM
        MeasureMenuItem(WindowID, Message, wParam, lParam)
      Case #WM_DRAWITEM
        DrawMenuItem(WindowID, Message, wParam, lParam)
    EndSelect
  ProcedureReturn Result
EndProcedure

OpenWindow(0, 0, 0, 512, 384, "", #PB_Window_ScreenCentered | #PB_Window_SystemMenu)
CreateGadgetList(WindowID(0))
SetWindowCallback(@MainWindowCallback(), 0)
  CreateMenu(0, WindowID(MainWindow))
    MenuTitle("&File")
      MenuItemEx(00, "&Open", LoadImage(-1, "folder-open_16.ico"))
  

Repeat
  Select WaitWindowEvent()
    Case #PB_Event_CloseWindow
      Break
  EndSelect
ForEver




Posted: Wed Apr 25, 2007 9:08 am
by Joakim Christiansen
Thanks, works fine for icons. But what should I modify to be able to use bitmaps? (sorry, I'm a noob at this)

Posted: Wed Apr 25, 2007 9:58 am
by Trond
Use BitBlt_() instead of DrawIconEx_(). Or just convert your bitmaps to icons.

Posted: Wed Apr 25, 2007 11:21 am
by Joakim Christiansen
Trond wrote:Use BitBlt_() instead of DrawIconEx_().
Didn't work.
Trond wrote:Or just convert your bitmaps to icons.
Looks like I have to do that.

Posted: Wed Apr 25, 2007 5:28 pm
by Trond
Joakim Christiansen wrote:
Trond wrote:Use BitBlt_() instead of DrawIconEx_().
Didn't work.
BitBlt_() will work if used correctly, but the included code is probably wrong.

Posted: Thu Apr 26, 2007 7:01 pm
by Joakim Christiansen
Trond wrote:BitBlt_() will work if used correctly, but the included code is probably wrong.
Okay, I got it to work.
But that code you shared is kinda gay, since it doesn't work with multiple menues (I want to use it for popup menues too). But it always uses MenuID(0)...
Is there any easy way to fix this? :?

Posted: Thu Apr 26, 2007 9:23 pm
by Trond
I don't get a #WM_DRAWITEM for popup menus, so the drawing procedure is never triggered. But apart from that, just change menuid(0) into *DrawItem\hwndItem.

Posted: Thu Apr 26, 2007 11:12 pm
by Joakim Christiansen
Looks like I'm getting it to work quite ok now, so thanks for the help!
But in the MeasureMenuItem procedure I can't use *DrawItem\hwndItem so it ain't measured right.

Posted: Fri May 04, 2007 8:52 pm
by Joakim Christiansen
Trond wrote:I don't get a #WM_DRAWITEM for popup menus, so the drawing procedure is never triggered. But apart from that, just change menuid(0) into *DrawItem\hwndItem.
Works fine with my popup menues :?

But in the MeasureMenuItem() procedure at:

Code: Select all

GetMenuString_(MenuID(0), *MeasureItem\itemID, @Text, 8192, 0)
I can't seem to find a way for it to find the right MenuID for the menu, if it's possible it would be nice to know the sollution? This is actually halting one of my projects...

Posted: Fri May 04, 2007 9:48 pm
by Trond
It should be possible to replace it with *DrawItem\hwndItem. What happens when you do that?

Posted: Fri May 04, 2007 10:34 pm
by Joakim Christiansen
Trond wrote:It should be possible to replace it with *DrawItem\hwndItem. What happens when you do that?
The MeasureMenuItem() procedure doesn't have an *DrawItem pointer but I have tried creating one and do what you suggested and it didn't work.