Page 1 of 1

Menu Icons (The easy way! Vista+)

Posted: Wed May 05, 2010 3:22 am
by Rescator
There are a few menu icon sources on the forums, all of them are owner drawn. (only way to get nice looking icons in front of menu items)

PureBasic's native icon menu is nice, but I never liked the color stripe, and the highlight color clashes a little with the text color etc.
And it does not match the system menu visual style, there may be some usability issues with it too. (after all it's ownerdrawn, meaning the coder need to do most of the work)

I began thinking... I want the Windows OS menu, but with icons in front of items.
Can't be THAT hard can it? Erm.. yeah it can...
Unless you use the source below and use it on Windows 6.0+ (Vista+), in which case it's pretty easy.

AddImageToMenuItem() will copy the current image, creating a new one.
If the icon was copied/created/added to the menu sucessfully then AddImageToMenuItem() will return a handle to a image, otherwise it returns #Null.
When you are done with the menu (and the icon) just use FreeImage() to free it.
You must also use FreeImage() if you plan to replace the menu icon, if you do not then you will end up with a memory leak.

Maybe Fred will support this type of icons in the future on Vista+, but until then this is as good as it gets. (unless someone here can improve on this further)

Why this messing around with copying and freeing?
Well it's because (and I have no idea why really it has to be like this, seems silly if you ask me) is the Vista+ need the icons (or image rather) to be a 32bit image with alpha mask,
but the RGBA must actually be pre-multiplied alpha pixels.
If it wasn't for that little annoyance then this would have needed only a few lines, instead of half a page.

So how is this better than owner drawn? Well I pointed that out earlier. Let's just say that this lets you use the "normal" menu, it works with both the window menu and the popup menu, and looks best with the popup menu as you can display icons for the root items properly as well. (window menu has some issues with that but subitems/submenus are ok).
Vista, 2008, Windows 7, 2008R2 will show the proper theme/coloring just like normally, accelerator keys works, etc etc..
The real shame however is that Microsoft didn't get a chance to add the 32bit RGBA image icon feature in W2K and XP and W2K3. Then again, XP is about 10 years old now so...*shrug*

And in the hopes this gets really popular I place this in the Public Domain, have fun folks!

If you need a good consistent and free set of menu icons etc.
Check out http://tango.freedesktop.org/Tango_Desktop_Project the icons are public domain, but I still advise that you credit the project in your program or documentation somewhere.
Best of all is that these icons come in 16x16 and 32x32 and they are 32bit Alpha PNG's, so they can be used with the code below (sorry, still need pre-multiply the alpha though)
and they look damn great.

Code: Select all

Structure BM_RGBA
	r.a
	g.a
	b.a
	a.a
EndStructure
Procedure.i AddImageToMenuItem(menu.i,item.i,image.i)
	Define result.i=#Null,mii.MENUITEMINFO,hmenu.i,imageid.i,bmp.BITMAP,*bm.BM_RGBA,*bmend,i.i,ii.i,imagepargb.i
	Static Dim rgbalpha_lookup.a(255,255)
	If OSVersion()>=#PB_OS_Windows_Vista ;Windows 6.0+ (Vista+)
		If rgbalpha_lookup(255,255)<>255
			For i=0 To 255
				For ii=0 To 255
					rgbalpha_lookup(i,ii)=Round(i*(ii/255.0),#PB_Round_Nearest)
				Next
			Next
		EndIf
		If IsMenu(menu) And IsImage(image)
			hmenu=MenuID(menu)
			imagepargb=CopyImage(image,#PB_Any)
			If IsImage(imagepargb)
				imageid=ImageID(imagepargb)
				GetObject_(imageid,SizeOf(BITMAP),bmp)
				If bmp And (bmp\bmWidth+bmp\bmWidth)>0 And bmp\bmBits
					*bm=bmp\bmBits
					*bmend=*bm+((bmp\bmWidth*bmp\bmHeight)<<2)
					Repeat
						*bm\r=rgbalpha_lookup(*bm\r,*bm\a)
						*bm\g=rgbalpha_lookup(*bm\g,*bm\a)
						*bm\b=rgbalpha_lookup(*bm\b,*bm\a)
						*bm+SizeOf(BM_RGBA)
					Until *bm>=*bmend
					mii\cbSize=SizeOf(mii)
					mii\fMask=#MIIM_BITMAP
					mii\hbmpItem=imageid
					If SetMenuItemInfo_(hmenu,item,#False,mii)
						result=imagepargb
					EndIf
				Else
					result=#Null
				EndIf
				If result=#Null
					FreeImage(imagepargb)
				EndIf
			EndIf
		EndIf
	EndIf
	Procedurereturn result
EndProcedure

Re: Menu Icons (The easy way! Vista+)

Posted: Wed May 05, 2010 8:06 pm
by iostream
I think some code is missing in line 36?

Re: Menu Icons (The easy way! Vista+)

Posted: Wed May 05, 2010 8:29 pm
by Edwin Knoppert
Not sure what you mean but i am very interested.
I played with setting an image to a menu 2 weeks ago and only under W7 (i skipped Vista) it looks good but there is a side effect, the menuheight get's less.

I am really an XP user and i started with XP, same problem but there are more issues:
1) The icon size (afaik) needs to be smaller than 16px, i believe 13px.
2) Menuheight decreases due the image height set.
3) Highlighted items are drawn incorrect (but liveable imo) since XP uses the menucolor to create transparancy and becuase this is a systemsetting(user) you can not create images for this situation properly.

And more, i haven't tested this situation under w7 with different themes and themes turned off.

Hope to hear more since i also like default drawn menus.

Re: Menu Icons (The easy way! Vista+)

Posted: Thu May 06, 2010 4:54 am
by Rescator
iostream wrote:I think some code is missing in line 36?
Oops! a lil' copy'n'paste slipup. Just delete that one. Updated the first post.
I was testing various mii\ stuff there.
Edwin Knoppert wrote:Not sure what you mean but i am very interested.
I played with setting an image to a menu 2 weeks ago and only under W7 (i skipped Vista) it looks good but there is a side effect, the menuheight get's less.

I am really an XP user and i started with XP, same problem but there are more issues:
1) The icon size (afaik) needs to be smaller than 16px, i believe 13px.
2) Menuheight decreases due the image height set.
3) Highlighted items are drawn incorrect (but liveable imo) since XP uses the menucolor to create transparancy and becuase this is a systemsetting(user) you can not create images for this situation properly.

And more, i haven't tested this situation under w7 with different themes and themes turned off.

Hope to hear more since i also like default drawn menus.
You can only use the above function with Vista or 2008 or Win 7.
Although it accidentally works on XP the transparency/alpha blending is wrong, and it's squished between the checkmark and menu item.
So don't bother using this on XP.

As for icon size.. Well you can't use real icons on this way, you are basically handing 32bit alpha images, I suggest 32bit PNG's with alpha.
And for standard and small DPI 16x16 image should look ok, and for high DPI 32x32 image should look ok.

you are talking about image height, so I assume you mean the menu strip at top of windows.
As I mention in the initial post here, it looks really weird and glitchy if you try that, so on the window menu only use images on the child menu/elements.
The popup menu on the other hand can have an image on all items even the root ones.

This is how you'd use it.

Code: Select all

If CreatePopupMenu(0)
  MenuItem(1, "Cut")
  MenuItem(2, "Copy")
  MenuItem(3, "Paste")
  MenuBar()
  OpenSubMenu("Options")
    MenuItem(4, "Window...")
    MenuItem(5, "Gadget...")
  CloseSubMenu()
  MenuBar()
  MenuItem( 6, "Quit")
  AddImageToMenuItem(0,1,#MyImage_Icon_Cut)
  AddImageToMenuItem(0,2,#MyImage_Icon_Copy)
  AddImageToMenuItem(0,3,#MyImage_Icon_Paste)
  AddImageToMenuItem(0,4,#MyImage_Icon_Window)
  AddImageToMenuItem(0,5,#MyImage_Icon_Gadget)
  AddImageToMenuItem(0,6,#MyImage_Icon_Quit)
EndIf

;After the popup menu have been created and displayed you must use FreeImage() on the image handle returned by all the AddImageToMenuItem() calls.
;However if the menu remain unchanged until the end of the program then PureBasic will free the images.
A window menu strip:

Code: Select all

  If CreateMenu(0, WindowID(0))
    MenuTitle("File")
      MenuItem( 1, "&Load...")
      MenuItem( 2, "Save")
      MenuItem( 3, "Save As...")
      MenuBar()
      OpenSubMenu("Recents")
        MenuItem( 5, "Pure.png")
        MenuItem( 6, "Basic.jpg")
        OpenSubMenu("Even more !")
          MenuItem( 12, "Yeah")
        CloseSubMenu()
        MenuItem( 13, "Rocks.tga")
      CloseSubMenu()
      MenuBar()
      MenuItem( 7, "&Quit")

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

  EndIf

  AddImageToMenuItem(0,1,#MyImage_Icon_Load)
  AddImageToMenuItem(0,2,#MyImage_Icon_Save)
  AddImageToMenuItem(0,3,#MyImage_Icon_SaveAs)
  AddImageToMenuItem(0,5,#MyImage_Icon_Image)
  AddImageToMenuItem(0,6,#MyImage_Icon_Image)
  AddImageToMenuItem(0,12,#MyImage_Icon_Yeah)
  AddImageToMenuItem(0,13,#MyImage_Icon_Image)
  AddImageToMenuItem(0,7,#MyImage_Icon_Quit)
  AddImageToMenuItem(0,8,#MyImage_Icon_Cut)
  AddImageToMenuItem(0,9,#MyImage_Icon_Copy)
  AddImageToMenuItem(0,10,#MyImage_Icon_Paste)
  AddImageToMenuItem(0,11,#MyImage_Icon_About)

 ;If the window is to be closed/destroyed then you need to use FreeImage() on the image handle returned by all the AddImageToMenuItem() calls.
 ;However if the menu remain unchanged until the end of the program then PureBasic will free the images.

Re: Menu Icons (The easy way! Vista+)

Posted: Thu May 06, 2010 6:46 am
by Edwin Knoppert
No, i used a 13x13 (and others) bmp and set it to a menuitem, the menuitem height changes to the imageheight and appears smaller than the rest.

Re: Menu Icons (The easy way! Vista+)

Posted: Thu May 06, 2010 9:56 am
by Rescator
Ah! I just tested that. Yep! It's possible to even mix image sizes. Windows (Win7 I tested, and 2008 and Vista probably behave the same) will adjust the control area.
The text do not change just the clickable area, I guess it increases/decreases the top/bottom text margin...

Re: Menu Icons (The easy way! Vista+)

Posted: Thu May 06, 2010 12:01 pm
by Edwin Knoppert
First i would like to support XP as wel so a 13x13 is ok but the menuheight on XP as w7 changes to this imageheight.
Maybe we can find a way to restore the height with another call..

Re: Menu Icons (The easy way! Vista+)

Posted: Thu May 06, 2010 1:51 pm
by Rescator
Not really possible as only Windows 6.0+ support 32bit pre-multiplied alpha bitmaps.

If you want to do the same on Windows 5.0 (W2K, XP etc) then you must use ownerdrawn or PureBasic's Image menus.
The only image changes you can do on XP like this are the check mark states, but PureBasic handles that for you.

So sorry, but there simply is no way to do this using the system styled menus.
Even MicroSoft Office on XP uses ownerdrawn.

Just think of this as an incentive to upgrade to Vista or Windows 7 :P

I'm working on a program right now, on Vista+ it will have nice alpha images in the menu, on XP it will have nothing.
I kinda refuse to allow myself to use hacks or extensive re-coding just do add some feature to an older OS,
instead I take advantage of new features on a newer OS when available for an "enhanced" experience.
It's not like it changed the functionality or anything, the program works the same on both XP and Vista+,
it's just that it looks nicer on Vista+ ;)

Re: Menu Icons (The easy way! Vista+)

Posted: Thu May 06, 2010 2:11 pm
by Edwin Knoppert
But, afaik Windows 7 has not stated that you can use it this way.
The images are now drawn much better in w7 but afaik msdn still does not aprove color images..

Did you read something else?

Re: Menu Icons (The easy way! Vista+)

Posted: Thu May 06, 2010 2:16 pm
by Rescator
New in Windows Vista

In Windows XP, owner-draw menus show icons, but Windows Vista® uses alpha-blended bitmaps instead.
http://msdn.microsoft.com/en-us/library/bb757020.aspx

Re: Menu Icons (The easy way! Vista+)

Posted: Thu May 06, 2010 4:02 pm
by Edwin Knoppert
1)
>In Windows XP, owner-draw menus show icons, but Windows Vista® uses alpha-blended bitmaps instead.

I am long in the business but maybe i have a brain fart today?
if a menu is ownerdraw or not, what hicon handle are they talking about?
I am talking about the SetMenuItemInfo() API and always required a bmp handle.

2)
You must be careful because these examples are for theming mode, what if it's not themed, you may need alternative info.

Anyway, i am at this time not looking in the ownerdraw area but was trying to set a bitmap to a menu but preserving it's height.
Since the SetMenuItemInfo() API works for themed as not themed i thought this would be the easiest thing to try.
I have to reread where it says i can use full color in these menus without doing ownerdraw.
I did not understand them since if i am in ownerdraw i can draw whatever i please, icons, png etc.

Are we talking in different directions?

Edwin,