AutoHotkey Homepage AutoHotkey Community
Let's help each other out
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

assign bitmap to any item in any AHk menu
Goto page 1, 2  Next
 
Post new topic   Reply to topic    AutoHotkey Community Forum Index -> Scripts & Functions
View previous topic :: View next topic  
Author Message
shimanov



Joined: 25 Sep 2005
Posts: 612

PostPosted: Sun Jan 22, 2006 12:26 am    Post subject: assign bitmap to any item in any AHk menu Reply with quote

Work with context menu:

Code:

Menu, menuEmpty, Add

Menu, menuContext$Level2, Add, :menuEmpty
   Menu_AssignBitmap( "menuContext$Level2", 1, "coffee.bmp", true )
Menu, menuContext$Level2, Add, empty, :menuEmpty
Menu, menuContext$Level2, Add, world, :menuEmpty
   Menu_AssignBitmap( "menuContext$Level2", 3, "coffee.bmp", true )

Menu, menuContext, Add, empty 1, :menuEmpty
Menu, menuContext, Add, empty 2, :menuEmpty
   Menu, menuContext, Check, empty 2
   Menu_AssignBitmap( "menuContext", 2, "coffee.bmp", true, "coffee.bmp", false )
Menu, menuContext, Add, :menuContext$Level2

Gui, Show, x50 y50 w400 h200
return

GuiContextMenu:
   Menu, menuContext, Show
return


Work with Tray menu:

Code:

Menu, menuEmpty, Add

Menu, Tray, NoStandard
Menu, Tray, Add, Hello, :menuEmpty
   Menu_AssignBitmap( "Tray", 1, "coffee.bmp", true )
Menu, Tray, Add
Menu, Tray, Standard


Work with Window menu bar:

Code:

Menu, menuEmpty, Add

Menu, menuFile, Add, Hello, :menuEmpty
   Menu_AssignBitmap( "menuFile", 1, "coffee.bmp", false )

Menu, menuMain, Add, File, :menuFile

Gui, Menu, menuMain
Gui, Show, x50 y50 w400 h200


Code:

/*   p_menu            = "MenuName" (e.g., Tray, etc.)
   p_item            = 1, ...
   p_bm_unchecked,
   p_bm_checked      = path to bitmap/false
   p_unchecked_face,
   p_checked_face      = true/false (i.e., true = pixels with same color as first pixel are transparent)
*/
Menu_AssignBitmap( p_menu, p_item, p_bm_unchecked, p_unchecked_face=false, p_bm_checked=false, p_checked_face=false )
{
   static   h_menuDummy
   
   if h_menuDummy=
   {
      Menu, menuDummy, Add
      Menu, menuDummy, DeleteAll
      
      Gui, 99:Menu, menuDummy
      Gui, 99:Show, Hide, guiDummy

      old_DetectHiddenWindows := A_DetectHiddenWindows
      DetectHiddenWindows, on

      Process, Exist
      h_menuDummy := DllCall( "GetMenu", "uint", WinExist( "guiDummy ahk_class AutoHotkeyGUI ahk_pid " ErrorLevel ) )
      if ReportError( ErrorLevel or h_menuDummy = 0, "Menu_AssignBitmap: GetMenu", "h_menuDummy = " h_menuDummy )
         return, false

      DetectHiddenWindows, %old_DetectHiddenWindows%
      
      Gui, 99:Menu
      Gui, 99:Destroy
   }
   
   Menu, menuDummy, Add, :%p_menu%
   
   h_menu := DllCall( "GetSubMenu", "uint", h_menuDummy, "int", 0 )
   if ReportError( ErrorLevel or h_menu = 0, "Menu_AssignBitmap: GetSubMenu", "h_menu = " h_menu )
      return, false

   success := DllCall( "RemoveMenu", "uint", h_menuDummy, "uint", 0, "uint", 0x400 )
   if ReportError( ErrorLevel or ! success,  "Menu_AssignBitmap: RemoveMenu", "success = " success )
      return, false
   Menu, menuDummy, Delete, :%p_menu%
   
   if ( p_bm_unchecked )
   {
      hbm_unchecked := DllCall( "LoadImage"
                           , "uint", 0
                           , "str", p_bm_unchecked
                           , "uint", 0                           ; IMAGE_BITMAP
                           , "int", 0
                           , "int", 0
                           , "uint", 0x10|( 0x20*p_unchecked_face ) )   ; LR_LOADFROMFILE|LR_LOADTRANSPARENT
      if ReportError( ErrorLevel or ! hbm_unchecked, "Menu_AssignBitmap: LoadImage: unchecked", "hbm_unchecked = " hbm_unchecked )
         return, false
   }

   if ( p_bm_checked )
   {
      hbm_checked := DllCall( "LoadImage"
                           , "uint", 0
                           , "str", p_bm_checked
                           , "uint", 0
                           , "int", 0
                           , "int", 0
                           , "uint", 0x10|( 0x20*p_checked_face ) )
      if ReportError( ErrorLevel or ! hbm_checked, "Menu_AssignBitmap: LoadImage: checked", "hbm_checked = " hbm_checked )
         return, false
   }

   success := DllCall( "SetMenuItemBitmaps"
                     , "uint", h_menu
                     , "uint", p_item-1
                     , "uint", 0x400                              ; MF_BYPOSITION
                     , "uint", hbm_unchecked
                     , "uint", hbm_checked )
   if ReportError( ErrorLevel or ! success, "Menu_AssignBitmap: SetMenuItemBitmaps", "success = " success )
      return, false
   
   return, true
}

ReportError( p_condition, p_title, p_extra )
{
   if p_condition
      MsgBox,
         ( LTrim
            [Error] %p_title%
            EL = %ErrorLevel%, LE = %A_LastError%
            
            %p_extra%
         )
   
   return, p_condition
}


Last edited by shimanov on Thu Mar 23, 2006 5:21 am; edited 5 times in total
Back to top
View user's profile Send private message
Titan



Joined: 11 Aug 2004
Posts: 5009
Location: imaginationland

PostPosted: Sun Jan 22, 2006 12:50 am    Post subject: Reply with quote

Thats great! We don't have to wait for in-built support now Smile

I found one issue, bitmaps with magenta backgrounds are shown to have the magenta colour. It's supposed to be negated and treated as a transparent secion right?
Back to top
View user's profile Send private message Visit poster's website
shimanov



Joined: 25 Sep 2005
Posts: 612

PostPosted: Sun Jan 22, 2006 1:37 am    Post subject: Reply with quote

Titan wrote:
Thats great!


Thanks. It was a fun challenge to resolve.

Quote:
one issue, bitmaps with magenta backgrounds are shown to have the magenta colour. It's supposed to be negated and treated as a transparent secion right?


Why?

Do you have the following in mind:

MSDN:LoadImage wrote:

LR_LOADTRANSPARENT [=0x20]
Retrieves the color value of the first pixel in the image and replaces the corresponding entry in the color table with the default window color (COLOR_WINDOW). All pixels in the image that use that entry become the default window color. This value applies only to images that have corresponding color tables.
Do not use this option if you are loading a bitmap with a color depth greater than 8bpp.

If fuLoad includes both the LR_LOADTRANSPARENT and LR_LOADMAP3DCOLORS values, LRLOADTRANSPARENT takes precedence. However, the color table entry is replaced with COLOR_3DFACE rather than COLOR_WINDOW.
Back to top
View user's profile Send private message
Titan



Joined: 11 Aug 2004
Posts: 5009
Location: imaginationland

PostPosted: Sun Jan 22, 2006 2:56 pm    Post subject: Reply with quote

That's the one. I'm not sure how I'd impliment it though.
Back to top
View user's profile Send private message Visit poster's website
shimanov



Joined: 25 Sep 2005
Posts: 612

PostPosted: Sun Jan 22, 2006 8:31 pm    Post subject: Reply with quote

Titan:

Change each of the lines:

    , "uint", 0x10 ) ; LR_LOADFROMFILE


to

    , "uint", 0x10|0x20 ) ; LR_LOADFROMFILE|LR_LOADTRANSPARENT
Back to top
View user's profile Send private message
SKAN



Joined: 26 Dec 2005
Posts: 5574

PostPosted: Sun Jan 22, 2006 8:59 pm    Post subject: Reply with quote

"Splendid Job" Shimanov Very Happy

Menu_AssignBitmap() function is terrific, I tried it with my script`s tray menu and it looks so lively now!

Thanks for posting it.
_________________
SKAN - Suresh Kumar A N
Back to top
View user's profile Send private message
AGU
Guest





PostPosted: Sun Jan 22, 2006 10:10 pm    Post subject: Reply with quote

Hello shimanov,

thx for your script/function. Works great. I commented the script as far as I understood it and made some slight formating changes. I'm really trying to understand what the script is doing. Mr. Green
Attention: Further text below scriptcode
Code:
Menu_AssignBitmap(p_menu, p_path, p_bm_unchecked=false, p_bm_checked=false)
  {
    ; Thanks to shimanov for this function
    ; Details under http://www.autohotkey.com/forum/viewtopic.php?p=44577
   
    ; p_menu          : menu name
    ; p_path          : number of menu entry (1st entry = "1", 2nd entry = "2", ... )
    ; p_bm_unchecked  : path to .bmp for unchecked menu entry
    ; p_bm_checked    : path to .bmp for checked   menu entry
   
    static   menu_count, menu_list, h_menuDummy
   
    If h_menuDummy=
      {
        menu_count = 0
        menu_list = |
     
        ; Save current 'DetectHiddenWindows' mode to reset it later
        Old_DetectHiddenWindows := A_DetectHiddenWindows
        DetectHiddenWindows, on
       
        ; Retrieve scripts PID
        Process, Exist
        pid_this := ErrorLevel
       
        ; Create menuDummy and assign to Gui99
        Menu, menuDummy, Add
        Menu, menuDummy, DeleteAll
       
        Gui, 99:Menu, menuDummy
     
        ; Retrieve menu handle       
        h_menuDummy := DllCall( "GetMenu", "uint", WinExist( "ahk_class AutoHotkeyGUI ahk_pid " pid_this ) )
     
        ; Remove menu bar 'menuDummy'
        Gui, 99:Menu
       
        ; Reset 'DetectHiddenWindows' mode to old setting
        DetectHiddenWindows, %Old_DetectHiddenWindows%
      }
   
    If ( ! InStr( menu_list, "|" p_menu ",", false ) )
      {
        menu_count++
        menu_list = %menu_list%%p_menu%,%menu_count%|
       
        Menu, menuDummy, Add, :%p_menu%
      }
   
    root := InStr( menu_list, ",", false, InStr( menu_list, "|" p_menu ",", false ) ) + 1
    StringMid, root, menu_list, root, InStr( menu_list, "|", false, root ) - root
    p_path = %root%|%p_path%
   
    StringSplit, path, p_path, |
   
    ; Assign above retrieved menu handle to 'h_menu'
    h_menu := h_menuDummy
   
    loop, % path0 - 1
      h_menu := DllCall("GetSubMenu", "uint", h_menu, "int", path%A_Index% - 1)
   
    ; Load bitmap for unchecked menu entries
    If (p_bm_unchecked)
      {
        hbm_unchecked := DllCall( "LoadImage"
                                , "uint", 0
                                , "str", p_bm_unchecked
                                , "uint", 0               ; IMAGE_BITMAP
                                , "int", 0
                                , "int", 0
                                , "uint", 0x10 )          ; LR_LOADFROMFILE
       
        If (ErrorLevel or ! hbm_unchecked)
          {
             MsgBox, [Menu_AssignBitmap: LoadImage: unchecked] failed: EL = %ErrorLevel%
             Return, false
          }
      }
   
    ; Load bitmap for checked menu entries
    If (p_bm_checked)
      {
        hbm_checked := DllCall( "LoadImage"
                              , "uint", 0
                              , "str", p_bm_checked
                              , "uint", 0                 ; IMAGE_BITMAP
                              , "int", 0
                              , "int", 0
                              , "uint", 0x10 )            ; LR_LOADFROMFILE
     
        If (ErrorLevel or ! hbm_checked)
          {
             MsgBox, [Menu_AssignBitmap: LoadImage: checked] failed: EL = %ErrorLevel%
             Return, false
          }
      }
   
    ; On success assign image to menu entry
    success := DllCall( "SetMenuItemBitmaps"
                      , "uint", h_menu
                      , "uint", path%path0%-1
                      , "uint", 0x400                     ; MF_BYPOSITION
                      , "uint", hbm_unchecked
                      , "uint", hbm_checked )

    If (ErrorLevel or ! success)
      {
        MsgBox, [Menu_AssignBitmap: SetMenuItemBitmaps] failed: EL = %ErrorLevel%
        Return, false
      }
   
    Return, true
  }

However I've got some problems in understanding this little follwing passage. Just in case you like would you be so kind to write some explaining lines? Just for me that I can make some explaining comments.
Code:
    If ( ! InStr( menu_list, "|" p_menu ",", false ) )
      {
        menu_count++
        menu_list = %menu_list%%p_menu%,%menu_count%|
       
        Menu, menuDummy, Add, :%p_menu%
      }
   
    root := InStr( menu_list, ",", false, InStr( menu_list, "|" p_menu ",", false ) ) + 1
    StringMid, root, menu_list, root, InStr( menu_list, "|", false, root ) - root
    p_path = %root%|%p_path%
   
    StringSplit, path, p_path, |
   
    ; Assign above retrieved menu handle to 'h_menu'
    h_menu := h_menuDummy
   
    loop, % path0 - 1
      h_menu := DllCall("GetSubMenu", "uint", h_menu, "int", path%A_Index% - 1)


Cheers
AGU
Back to top
shimanov



Joined: 25 Sep 2005
Posts: 612

PostPosted: Mon Jan 23, 2006 1:04 am    Post subject: Reply with quote

AGU wrote:
I commented the script


Thank you. I really hate adding explicit comments. It's like doing the work twice.

Code:

   if ( ! InStr( menu_list, "|" p_menu ",", false ) )
   {
      menu_count++
      menu_list = %menu_list%%p_menu%,%menu_count%|
      
      Menu, menuDummy, Add, :%p_menu%
   }
   
   root := InStr( menu_list, ",", false, InStr( menu_list, "|" p_menu ",", false ) )+1
   StringMid, root, menu_list, root, InStr( menu_list, "|", false, root )-root
   p_path = %root%|%p_path%
   
   StringSplit, path, p_path, |


"Menu, menuDummy, Add, :%p_menu%" is where the magic happens. It attaches menus to a menu with a known handle (i.e., menuDummy) and enables retrieving its associated handle via "GetSubMenu" -- pretty cool.

The rest of the code manages the menu_list variable, which contains the menu names and their item position in menuDummy.

Code:

   h_menu := h_menuDummy
   loop, % path0-1
      h_menu := DllCall( "GetSubMenu", "uint", h_menu, "int", path%A_Index%-1 )


Determines menu handle for the requested menu and path on each call. This is necessary, but insufficient, to accommodate a deleted menu/item.
Back to top
View user's profile Send private message
shimanov



Joined: 25 Sep 2005
Posts: 612

PostPosted: Mon Jan 23, 2006 3:14 am    Post subject: update: 2006.01.22 Reply with quote

changes:
    * support transparent bitmaps (as suggested by Titan)
Back to top
View user's profile Send private message
AGU
Guest





PostPosted: Mon Jan 23, 2006 2:06 pm    Post subject: Reply with quote

Hello again.

Quote:
p_path = relative to p_menu (e.g., 3|1|2 = level 1: item 3|level 2: item 1|level 3: item 2)
Do I understand right, that I can assign more than one bitmap at once?

Concerning the support for transparent bitmaps:
How does that work? I add a bitmap and the first pixel (x1 * y1) becomes the transparent color for the whole bitmap? The transparent color pixels get the same color as the menu background when I understand that right.

I used bitmaps with white background and didn't make use of LR_LOADTRANSPARENT. But the background gets transparent, too. Why? Is that because you should use monochrome bitmaps normally? MSDN said s.th about this and that by using monochrome bitmaps the white background gets transparent.

Another thing:
What's the max-size for these bitmaps. I realized that 16x16 bitmaps get cut when you add them to a context menu. 13x13px is the maxsize I could use for context menus. Is that normal? And why don't they just scale to the correct size instead of getting cut?

Cheers
AGU
Back to top
shimanov



Joined: 25 Sep 2005
Posts: 612

PostPosted: Mon Jan 23, 2006 8:27 pm    Post subject: Reply with quote

AGU wrote:
Do I understand right, that I can assign more than one bitmap at once?


Two different bitmaps can be assigned to each item, one for unchecked and one for checked.

Quote:
Concerning the support for transparent bitmaps


Refer to my earlier post containing a description of the LR_LOADTRANSPARENT flag.

Quote:
What's the max-size for these bitmaps.


Code:

SysGet, w, 71
SysGet, h, 72

MsgBox, %w%, %h%
Back to top
View user's profile Send private message
Guest






PostPosted: Tue Jan 24, 2006 4:56 pm    Post subject: Reply with quote

Quote:
Two different bitmaps can be assigned to each item, one for unchecked and one for checked.
Yeah I know. But I understand the following line in this way, that you assign these two bitmaps to three different items namely:

"level 1: item 3",
"level 2: item 1"
"level 3: item 2"
Quote:
p_path = relative to p_menu (e.g., 3|1|2 = level 1: item 3|level 2: item 1|level 3: item 2)

I understand it in the way that you assign 3 * 2(per item) = 6 pictures at once. My question aims at if I understood that right.
So, did I? Can you, by using "|", assign bitmaps to multiple entries on different menu layers (submenus)?

Cheers
AGU
Back to top
shimanov



Joined: 25 Sep 2005
Posts: 612

PostPosted: Tue Jan 24, 2006 8:08 pm    Post subject: Reply with quote

Anonymous wrote:
assign these two bitmaps to three different items namely:

"level 1: item 3",
"level 2: item 1"
"level 3: item 2"


Now I understand your question. The path allows specification of a single item located on a submenu n-levels removed from a top level menu.

There are two ways to specify an item:

Code:

Menu, < level 2 >, Add, item 1, ...

Menu, < level 1 >, Add, item 2, :< level 2 >

; direct
Menu_AssignBitmap( "< level 2 >", "1", ... )

; indirect
Menu_AssignBitmap( "< level 1 >", "2|1", ... )


The difference between the two method is purely stylistic.

Now that I think about it, the technique used to determine the handle of submenus, obviates the need for a path specification. I'll have to update the code to reflect this capability.
Back to top
View user's profile Send private message
AGU
Guest





PostPosted: Tue Jan 24, 2006 8:31 pm    Post subject: Reply with quote

Ahhh, thx now i got it.

Some short kind of documentation won't be that bad. Wink

Cheers
AGU

P.S. looking forward to your code update.
Back to top
shimanov



Joined: 25 Sep 2005
Posts: 612

PostPosted: Tue Jan 24, 2006 8:50 pm    Post subject: update: 2006.01.24 Reply with quote

changes:
    * simplified item specification method (removed indirect method)


Thanks to AGU for keeping me on my toes.
Back to top
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic    AutoHotkey Community Forum Index -> Scripts & Functions All times are GMT
Goto page 1, 2  Next
Page 1 of 2

 
Jump to:  
You can post new topics in this forum
You can reply to topics in this forum


Powered by phpBB © 2001, 2005 phpBB Group