Jump to content


Photo

ILButton() - image buttons with text, states, alignment


  • Please log in to reply
48 replies to this topic

#1 tkoi

tkoi
  • Members
  • 56 posts

Posted 01 February 2009 - 05:40 PM

First of all, I want to say thanks a bunch to corrupt for his excellent graphic button functions. I've used them extensively. However, I found a few aspects lacking.

The most glaring problem is the limitations on Windows XP. On XP, buttons with the BM_SETIMAGE message do not assume the OS's visual style, which can end up looking downright ugly if you have both text buttons and image buttons in your app. These buttons also are incapable of displaying an image+text.

BM_SETIMAGE buttons do not have native support for button states (hover, disabled, etc) or image alignment.

So with these flaws in mind, I went searching for a better way to create an image button. What I found was the BCM_SETIMAGELIST message. This attaches an imagelist to a button, and, combined with a few dllcall functions, allows for more flexible and customizable image buttons. I've written a single small function wrapping most of the options that are available.

Features[*:346l8jia] Supports exe, dll, ico, cur, ani, and bmp files
[*:346l8jia] Button states: normal, hover, pressed, disabled, focused, and stylushot
[*:346l8jia] Supports image+text
[*:346l8jia] Supports visual styles on Windows XP
[*:346l8jia] Alignment options: left, right, top, bottom, or center - very useful for image+text buttons
[*:346l8jia] Image margin options
[*:346l8jia] Creates no global variablesPosted Image_Posted Image

Download: ILButton11.ahk
/*
Title: ILButton
Version: 1.1
Author: tkoi <http://www.autohotkey.net/~tkoi>
License: GNU GPLv3 <http://www.opensource.org/licenses/gpl-3.0.html>

Function: ILButton()
    Creates an imagelist and associates it with a button.
Parameters:
    hBtn   - handle to a buttton
    images - a pipe delimited list of images in form "file:zeroBasedIndex"
               - file must be of type exe, dll, ico, cur, ani, or bmp
               - there are six states: normal, hot (hover), pressed, disabled, defaulted (focused), and stylushot
                   - ex. "normal.ico:0|hot.ico:0|pressed.ico:0|disabled.ico:0|defaulted.ico:0|stylushot.ico:0"
               - if only one image is specified, it will be used for all the button's states
               - if fewer than six images are specified, nothing is drawn for the states without images
               - omit "file" to use the last file specified
                   - ex. "states.dll:0|:1|:2|:3|:4|:5"
               - omitting an index is the same as specifying 0
               - note: within vista's aero theme, a defaulted (focused) button fades between images 5 and 6
    cx     - width of the image in pixels
    cy     - height of the image in pixels
    align  - an integer between 0 and 4, inclusive. 0: left, 1: right, 2: top, 3: bottom, 4: center
    margin - a comma-delimited list of four integers in form "left,top,right,bottom"

Notes:
    A 24-byte static variable is created for each IL button
    Tested on Vista Ultimate 32-bit SP1 and XP Pro 32-bit SP2.

Changes:
  v1.1
    Updated the function to use the assume-static feature introduced in AHK version 1.0.48
*/

ILButton(hBtn, images, cx=16, cy=16, align=4, margin="1,1,1,1") {
	static
	static i = 0
	local himl, v0, v1, v2, v3, ext, hbmp, hicon
	i ++

	himl := DllCall("ImageList_Create", "UInt",cx, "UInt",cy, "UInt",0x20, "UInt",1, "UInt",5)
	Loop, Parse, images, |
		{
		StringSplit, v, A_LoopField, :
		if not v1
			v1 := v3
		v3 := v1
		SplitPath, v1, , , ext
		if (ext = "bmp") {
			hbmp := DllCall("LoadImage", "UInt",0, "Str",v1, "UInt",0, "UInt",cx, "UInt",cy, "UInt",0x10)
			DllCall("ImageList_Add", "UInt",himl, "UInt",hbmp, "UInt",0)
			DllCall("DeleteObject", "UInt", hbmp)
			}
		else {
			DllCall("PrivateExtractIcons", "Str",v1, "UInt",v2, "UInt",cx, "UInt",cy, "UIntP",hicon, "UInt",0, "UInt",1, "UInt",0)
			DllCall("ImageList_AddIcon", "UInt",himl, "UInt",hicon)
			DllCall("DestroyIcon", "UInt", hicon)
			}
		}
	; Create a BUTTON_IMAGELIST structure
	VarSetCapacity(struct%i%, 24)
	NumPut(himl, struct%i%, 0, "UInt")
	Loop, Parse, margin, `,
		NumPut(A_LoopField, struct%i%, A_Index * 4, "UInt")
	NumPut(align, struct%i%, 20, "UInt")
	; BCM_FIRST := 0x1600, BCM_SETIMAGELIST := BCM_FIRST + 0x2
	PostMessage, 0x1602, 0, &struct%i%, , ahk_id %hBtn%
	Sleep 1 ; workaround for a redrawing problem on WinXP
	}
Download: ilbuttondemo.ahk
#SingleInstance force
#NoEnv

#Include %A_ScriptDir%\ILButton.ahk

Gui, +ToolWindow +AlwaysOnTop
Loop 5 {
	Gui, Add, Button, w64 h32 xm hwndhBtn
		ILButton(hBtn, "user32.dll:" A_Index-1, 16, 16, A_Index-1)
	Gui, Add, Button, w100 h32 x+10 hwndhBtn, text
		ILButton(hBtn, "user32.dll:" A_Index-1, 16, 16, A_Index-1)
	}
Gui, Add, Button, xm w174 h48 vStates hwndhBtn, pushbuttonstates
	ILButton(hBtn, "user32.dll:0|:1|:2|:3|:4|:5", 32, 32, 0, "16,1,-16,1")
Gui, Add, Button, w100 h26 xm+74 gToggle, Enable/disable

Gui, Show, , ILButton demo
return

Toggle:
	GuiControlGet, s, Enabled, States
	GuiControl, Disable%s%, States
	return

GuiClose:
GuiEscape:
	ExitApp
	return
Please post any bugs you find!

Regards,
tkoi

#2 BoBo³

BoBo³
  • Guests

Posted 02 February 2009 - 12:44 AM

Thanks for sharing your script(s). Much appreciated :D

#3 SKAN

SKAN
  • Administrators
  • 9062 posts

Posted 02 February 2009 - 02:13 PM

Great! Thanks. :)

#4 Laszlo

Laszlo
  • Fellows
  • 4713 posts

Posted 02 February 2009 - 03:33 PM

Very nice!
Could you extend it, such that the associated system icon of the file would be shown, e.g. when the icon number is -1?

#5 Laszlo

Laszlo
  • Fellows
  • 4713 posts

Posted 02 February 2009 - 06:06 PM

The command VarSetCapacity(structs, c+24) looks suspicious:

It allocates larger and larger memory blocks, but each time the previous data can be lost. In this script the old data might be preserved, because struct is the last static variable, so its memory is just increased, but this behavior might change in a future AHK version or when the memory pool dries out. Since we have no static arrays, we probably have to use an array of global structs.

To demonstrate the problem, add VarSetCapacity(c, c+24) to the code. Now the struct variable cannot be just enlarged, and the script breaks.

#6 majkinetor !

majkinetor !
  • Guests

Posted 04 February 2009 - 02:44 PM

Great discovery. I traversed all API places around for the solution regarding system bug with button images but I didn't see this one.

IT works in XP too, but here icons appear only when i mouse over them. Seems like an easy thing to solve anyway.

Thx.

#7 Laszlo

Laszlo
  • Fellows
  • 4713 posts

Posted 05 February 2009 - 04:16 PM

IT works in XP too, but here icons appear only when i mouse over them.

On my XP laptop changing Sleep -1 to Sleep 1 (last line) fixes the problem.

#8 majkinetor

majkinetor
  • Fellows
  • 4511 posts

Posted 05 February 2009 - 07:24 PM

:)

Thx

#9 jballi

jballi
  • Members
  • 940 posts

Posted 06 February 2009 - 12:50 AM

Looks useful. Thanks for sharing. :)

#10 webber

webber
  • Members
  • 129 posts

Posted 23 February 2009 - 11:31 PM

testing this tool but I'm unable to use a specific icon. the icon image is in the same folder as script

can someone tell me why this line fails to return an image ?


Gui, 2:Add, Button, x16 y50  w100 h30 hwndhBtn gButtonTool_1, Tool_2
		ILButton(hBtn, "icon6-16x16C.ico:0" 1, 16, 16, 0)

________
DRUGTEST

#11 tkoi

tkoi
  • Members
  • 56 posts

Posted 24 February 2009 - 02:55 AM

What's that 1 doing there? :D
Gui, 2:Add, Button, x16 y50  w100 h30 hwndhBtn gButtonTool_1, Tool_2
      ILButton(hBtn, "icon6-16x16C.ico:0" [color=red]1[/color], 16, 16, 0)


#12 webber

webber
  • Members
  • 129 posts

Posted 24 February 2009 - 03:30 AM

image is not appearing on the button - that's what I doing there.

so the question is, why no image from the code ?

#13 tkoi

tkoi
  • Members
  • 56 posts

Posted 24 February 2009 - 04:01 AM

I tested it - it works if you remove the 1.

#14 webber

webber
  • Members
  • 129 posts

Posted 25 February 2009 - 06:00 AM

:oops:
________
Chevrolet colorado

#15 tkoi

tkoi
  • Members
  • 56 posts

Posted 26 February 2009 - 01:32 AM

Updated - the function now uses the assume-static mode introduced in 1.0.48