Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate
Photo

Menu Icons v2


  • Please log in to reply
138 replies to this topic
Lexikos
  • Administrators
  • 9844 posts
  • AutoHotkey Foundation
  • Last active:
  • Joined: 17 Oct 2006
Menu Icons
Allows scripts to add icons to menu items.

Note: Most users would be better off using AutoHotkey_L's built-in menu icon support.

MI.ahk
public domain
 

Usage

Download MI.ahk and place it in your Lib folder. MI_SetMenuItemIcon() is the main function. Usage is explained in MI.ahk.
 

Known Issues
 
Using MI_EnableOwnerDrawMenus on the script's main window:
  • breaks the "Pause Script" menu item; and
  • makes ListLines less useful, since interacting with the main window causes script to execute.
  • AutoHotkey 64-bit is not supported.
Examples
; Uncomment this if MI.ahk is not in your function library:
;#include %A_ScriptDir%\MI.ahk

#NoEnv

; Sample menu items.
Menu, M, Add, 16x16 Icon, ItemClick
Menu, M, Add, 32x32 Icon, ItemClick
Menu, M, Add, 48x48 Icon, ItemClick

; Set item 1's icon to shell32.dll, icon 4, 16x16.
MI_SetMenuItemIcon("M", 1, "shell32.dll", 4, 16)
; Set item 2's icon to shell32.dll, icon 4, 32x32.
MI_SetMenuItemIcon("M", 2, "shell32.dll", 4, 32)
; Windows 2000 or later required (supports sizes other than 16x16 and 32x32):
MI_SetMenuItemIcon("M", 3, "shell32.dll", 4, 48)
; Usually looks better:
MI_SetMenuStyle("M", 0x4000000)

; Note: This menu is shown automatically after setting up the tray menu.


;
; Icons in the Tray menu!
;
; Refer to a menu by handle for efficiency.
hTM := MI_GetMenuHandle("Tray")

if (A_OSVersion != "WIN_VISTA")
{   ; It is necessary to hook the tray icon for owner-drawing to work.
    ; (Owner-drawing is not used on Windows Vista.)
    OnMessage(0x404, "AHK_NOTIFYICON")
    OnMessage(0x111, "WM_COMMAND") ; To track "pause" status.
    MI_SetMenuStyle(hTM, 0x4000000) ; MNS_CHECKORBMP (optional)
}

SplitPath, A_AhkPath,, SpyPath
SpyPath = %SpyPath%\AU3_Spy.exe

MI_SetMenuItemIcon(hTM, 1, A_AhkPath, 1, 16) ; open
MI_SetMenuItemIcon(hTM, 2, A_WinDir "\hh.exe", 1, 16) ; help
;-
MI_SetMenuItemIcon(hTM, 4, SpyPath,   1, 16) ; spy
; reload - icon needed!
MI_SetMenuItemIcon(hTM, 6, A_AhkPath, 2, 16) ; edit
;-
MI_SetMenuItemIcon(hTM, 8, A_AhkPath, 3, 16) ; suspend
MI_SetMenuItemIcon(hTM, 9, A_AhkPath, 4, 16) ; pause
MI_SetMenuItemBitmap(hTM, 10, 8) ; exit


MI_ShowMenu("M")
return

ItemClick:
return


AHK_NOTIFYICON(wParam, lParam)
{
    global hTM, M_IsPaused
    if (lParam = 0x205) ; WM_RBUTTONUP
    {
        ; Update "Suspend Script" and "Pause Script" checkmarks.
        DllCall("CheckMenuItem","uint",hTM,"uint",65305,"uint",A_IsSuspended ? 8:0)
        DllCall("CheckMenuItem","uint",hTM,"uint",65306,"uint",M_IsPaused ? 8:0)
        ; Show menu to allow owner-drawing.
        MI_ShowMenu(hTM)
        return 0
    }
}

WM_COMMAND(wParam, lParam, Msg, hwnd)
{
    Critical
    global M_IsPaused
    id := wParam & 0xFFFF
    if id in 65306,65403  ; tray pause, file menu pause
    {
        ; When the script is not paused, WM_COMMAND() is called once for
        ; AutoHotkey --** and once for OwnerDrawnMenuMsgWin **--.
        DetectHiddenWindows, On
        WinGetClass, cl, ahk_id %hwnd%
        if cl != AutoHotkey
            return
        
        ; This will become incorrect if "pause" is used from the script.
        M_IsPaused := ! M_IsPaused
    }
}
 
Version History

v2.21 (2010-03-13)
  • Fixed: WM_COMMAND messages received by subclassed GUI windows were erroneously forwarded to the script's main window. This broke button gLabels.
  • Fixed: Unicode incompatibility in MI_ExtractIcon.v2.2 (2009-01-08)Changed MI_SetMenuItemIcons to automatically delete the previous icon or bitmap.
  • If individual menu items are to be removed, call MI_SetMenuItemIcons(MenuNameOrHandle, ItemPos, 0) to remove the icon.
  • Added MI_RemoveIcons, to be called before deleting a menu.
  • Misc optimizations (thanks animeaime).v2.1 (2007-12-25)Added MI_EnableOwnerDrawnMenus(), which can be used to enable owner-drawn menus for a given window (as an alternative to MI_ShowMenu().)
  • MI_SetMenuStyle() now accepts a menu name or handle.v2 (2007-10-19)Now stdlib compatible (added MI_ prefix to functions.)
  • Merged everything into MI.ahk, removing wrapper functions in the process.
Operating System Notes

On Windows Vista and later, the script generates a 32-bit device-independent bitmap. This allows nice transparency (alpha blending) in icons, and allows Vista's menu style to apply.

On earlier versions of Windows, this method is not supported. Instead, the menu icons are owner-drawn. ShowMenu() or ShowOwnerDrawnMenu() must be called to show the menu with icons. ShowOwnerDrawnMenu() creates an invisible message window to act as the menu's owner (once per instance of the script.) As a side effect, showing a menu should not make the script/thread uninterruptible.

On Windows 2000 and later, PrivateExtractIcons() is used by SetMenuItemIcon() to extract an icon from a file. This should support any size of icon (tested with 16, 32 and 48.)

ExtractIconEx() is used on earlier versions of Windows, as PrivateExtractIcons() is not available. This supports 16x16 and 32x32 icons only. Other sizes may be specified, but the icon will be stretched to fit, regardless of which sizes are available in the source file. (However, LoadImage() can still be used to load the first icon of any given size from an .ico file.)


References
Shell Blog: Vista Style Menus, Part 1 - Adding icons to standard menus
nanoANT: Themed menu’s icons, a complete Vista and XP solution


Note: I chose to write this rather than use MMenu because:
  • I did not want a whole new menu API.
  • MMenu exclusively uses owner-drawing for icons, which disables Windows Vista's menu styles.


Laszlo
  • Moderators
  • 4713 posts
  • Last active: Mar 31 2012 03:17 AM
  • Joined: 14 Feb 2005
Beautiful! Thanks for sharing it!

Hardeep
  • Members
  • 87 posts
  • Last active: Sep 12 2007 06:40 PM
  • Joined: 02 Jul 2006
Thanks for sharing your work. Really nice... :)

Chris
  • Administrators
  • 10727 posts
  • Last active:
  • Joined: 02 Mar 2004
I've been catching up in this forum and only just now saw this topic. Great presentation and intuitive interface! I know it will be popular.

I haven't studied your approach carefully enough to understand the differences between it and Majkinetor's MMenu 1.0 b1. In any case, I'm sure one or both would be great to include in the standard library.

Lexikos
  • Administrators
  • 9844 posts
  • AutoHotkey Foundation
  • Last active:
  • Joined: 17 Oct 2006
There are three main differences:[*:umw78i9k]It uses 32-bit bitmaps on Vista instead of owner-drawing the icon. This allows Vista to apply its menu styles.
[*:umw78i9k]It registers a window class and creates a message window to do the owner drawing, rather than using OnMessage. (I couldn't get OnMessage to catch the messages, though MMenu seems to. Also, I seem to recall majkinetor saying OnMessage sometimes misses the messages.)
[*:umw78i9k]It is intended for use with the existing Menu commands, whereas MMenu reimplements the interface (MMenu_Add, etc.):)

Great presentation and intuitive interface!

Thanks! It went through at least three or four function prototypes before I settled on the current interface. :lol:

Chris
  • Administrators
  • 10727 posts
  • Last active:
  • Joined: 02 Mar 2004
Thanks for the explanation. Since Vista is still relatively young, it's a pleasant surprise that you've provided a way to exploit menu styles from AutoHotkey.

By the way, a few months ago there were some improvements to Critical and OnMessage that may resolve the dropping of messages that Majkinetor mentioned.

Lexikos
  • Administrators
  • 9844 posts
  • AutoHotkey Foundation
  • Last active:
  • Joined: 17 Oct 2006

Since Vista is still relatively young, it's a pleasant surprise that you've provided a way to exploit menu styles from AutoHotkey.

It's mostly thanks to these two articles:
Shell Blog: Vista Style Menus, Part 1 - Adding icons to standard menus
nanoANT: Themed menu’s icons, a complete Vista and XP solution (also details using "checkmark" bitmaps, and owner-drawn icons.)

(also just added those links to my first post)

Sean
  • Members
  • 2462 posts
  • Last active: Feb 07 2012 04:00 AM
  • Joined: 12 Feb 2007
I didn't know of it. Great stuffs!
What do you think about extending it to customize also the foreground/background colors, and fonts too if not too much?
There was a related request here:
<!-- m -->http://www.autohotke...topic22317.html<!-- m -->

majkinetor
  • Moderators
  • 4512 posts
  • Last active: Jul 29 2016 12:40 AM
  • Joined: 24 May 2006
Thx for this lexikos and for informatin about internals you provided.

It registers a window class and creates a message window to do the owner drawing, rather than using OnMessage

Very nice. Back in time I didn't have RegisterCallback so OnMessage was the only way.

It is intended for use with the existing Menu commands, whereas MMenu reimplements the interface

I never liked Menu API of AHK, as they are not practical for dynamic menus I had in some of my scripts. MMenu API allows much better control of the menu and its items.


BTW, is it possible to merge includes, and to provide some docu about API?
Posted Image

Lexikos
  • Administrators
  • 9844 posts
  • AutoHotkey Foundation
  • Last active:
  • Joined: 17 Oct 2006

BTW, is it possible to merge includes, and to provide some docu about API?

It is possible. ;) There are only functions, so merging them should be no problem. It would probably make it easier to #include (at the moment you need #Include path\to\MI\directory), but I like to have them seperate for organisation sake. Perhaps I'll simply provide two versions, when I get time.

As for documentation, what did you have in mind? Is there anywhere the comments are particularly lacking?

What do you think about extending it to customize also the foreground/background colors, and fonts too if not too much?

At the moment, the menu isn't exactly owner-drawn, just the icons (the item's bitmap is set to HBMMENU_CALLBACK.) I'll think about adding full owner-draw capabilities. :)

Sean
  • Members
  • 2462 posts
  • Last active: Feb 07 2012 04:00 AM
  • Joined: 12 Feb 2007

I'll think about adding full owner-draw capabilities.

Good, then I don't have to. I was thinking about implementing owner-drawn menu myself, but there was no real motivation for me as I've had fully fledged custom menu system for years.

Lexikos
  • Administrators
  • 9844 posts
  • AutoHotkey Foundation
  • Last active:
  • Joined: 17 Oct 2006
Updated. v2 is stdlib compatible, and entirely contained within MI.ahk.
I also added icons to the tray menu of the example script.
See my first post for a download link and new screenshot.

I'll think about adding full owner-draw capabilities.

Good, then I don't have to. I was thinking about implementing owner-drawn menu myself, but there was no real motivation for me as I've had fully fledged custom menu system for years.

Well, I thought about it for a while. :p I decided I wasn't satisfied enough with the Windows menu system to do anything further with it. I might eventually create something functionally (but not aesthetically) equivalent, using layered windows...

majkinetor!
  • Guests
  • Last active:
  • Joined: --
Great, thx !

nitrix
  • Guests
  • Last active:
  • Joined: --
this is a really great tool, thanks for sharing

BUT i do have a problem with the MI_SetMenuStyle
no matter what i choose, i does not change a thing :

; Valid (and safe to use) styles:
; MNS_AUTODISMISS 0x10000000
; MNS_CHECKORBMP 0x04000000 The same space is reserved for the check mark and the bitmap.
; MNS_NOCHECK 0x80000000 No space is reserved to the left of an item for a check mark.

i used to use Shimanov's Menu_AssignBitmap() without this problem

what i want to do is to remove the space on the left of the icons... so that my menu is more compact and menu item are not stripped

i use xp, most recent autohotkey release...

Nitrix

Lexikos
  • Administrators
  • 9844 posts
  • AutoHotkey Foundation
  • Last active:
  • Joined: 17 Oct 2006

BUT i do have a problem with the MI_SetMenuStyle
no matter what i choose, i does not change a thing :

I use:
h_Root := MI_GetMenuHandle("Root")
;...
MI_SetMenuStyle(h_Root, 0x04000000) ; MNS_CHECKORBMP
MI_SetMenuStyle does not support menu names, hence MI_GetMenuHandle.