
CreateImageButton.ahk:
; ======================================================================================================================
; AHK 1.1 +
; ======================================================================================================================
; Function: Create images and assign them to be shown within pushbuttons.
; AHK version: 1.1.05.05 (U32 / U64)
; Language: English
; Tested on: Win XPSP3, Win VistaSP2 (32 bit), Win 7 (64 bit)
; Version: 0.9.00.01/2011-04-02/just me
;
; How to use: 1. Create a push button with e.g. "Gui, Add, Button, vMyButton hwndHwndButton, Caption" using the
; hwnd option to get its HWND.
;
; 2. Call CreateImageButton passing up to three parameters:
; Mandatory:
; HWND - Button's HWND (Pointer)
; Options - 1-based array containing up to 6 option objects (Object)
; see below
; Optional:
; Margins - Distance between the bitmaps and the border in pixel (Integer)
; to keep parts of Windows' button animation visible
; Valid values: 0, 1, 2, 3, 4
; Default: 0
;
; The index of each option object determines the corresponding button state on which the bitmap
; will be shown. MSDN defines 6 states (http://msdn.microsoft.com/en-us/windows/bb775975):
; enum PUSHBUTTONSTATES {
; PBS_NORMAL = 1,
; PBS_HOT = 2,
; PBS_PRESSED = 3,
; PBS_DISABLED = 4,
; PBS_DEFAULTED = 5,
; PBS_STYLUSHOT = 6, <- used only on tablet computers
; };
; If you don't want the button to be "animated", just pass one option object with index 1.
;
; Each option object may contain the following key/value pairs:
; Mandatory:
; BC - Background Color(s):
; 6-digit RGB hex value ("RRGGBB") or HTML color name ("Red").
; Pass 2 pipe (|) separeted values for start and target colors of a gradient.
; If only one color is passed for 3D = 1 thru 3, black ("000000") will be used
; as default start color and the color value will be used as target color.
; In case of 3D = 9 BC must contain a picture's path or HBITMAP handle
; Optional:
; TC - Text Color:
; 6-digit RGB hex value ("RRGGBB") or HTML color name ("Red").
; Default: "000000" (black)
; 3D - 3D Effects:
; 0 = none (just colored)
; 1 = raised
; 2 = vertical "3D" gradient
; 3 = horizontal "3D" gradient
; 9 = background picture (BC contains the picture's path or HBITMAP handle)
; Default: 0
; G - Gamma Correction:
; 0 = no
; 1 = yes
; Default: 0
;
; Whenever the The button has a caption it is drawn above the bitmap or picture.
;
; Credits: THX tic for GDIP.AHK : http://www.autohotkey.com/forum/post-198949.html
; THX tkoi for ILBUTTON.AHK : http://www.autohotkey.com/forum/topic40468.html
; THX Lexikos for AHK_L
; ======================================================================================================================
; This software is provided 'as-is', without any express or implied warranty.
; In no event will the authors be held liable for any damages arising from the use of this software.
; ======================================================================================================================
; ======================================================================================================================
; FUNCTION CreateImageButton()
; ======================================================================================================================
CreateImageButton(HWND, Options, Margins = 0) {
; HTML colors
Static HTML := {BLACK: "000000", GRAY: "808080", SILVER: "C0C0C0", WHITE: "FFFFFF"
, MAROON: "800000", PURPLE: "800080", FUCHSIA: "FF00FF", RED: "FF0000"
, GREEN: "008000", OLIVE: "808000", YELLOW: "FFFF00", LIME: "00FF00"
, NAVY: "000080", TEAL: "008080", AQUA: "00FFFF", BLUE: "0000FF"}
; Windows constants
Static BS_CHECKBOX := 0x2 , BS_RADIOBUTTON := 0x4
, BS_GROUPBOX := 0x7 , BS_AUTORADIOBUTTON := 0x9
, BS_LEFT := 0x100 , BS_RIGHT := 0x200
, BS_CENTER := 0x300 , BS_TOP := 0x400
, BS_BOTTOM := 0x800 , BS_VCENTER := 0xC00
, BS_BITMAP := 0x0080
, SA_LEFT := 0x0 , SA_CENTER := 0x1
, SA_RIGHT := 0x2 , WM_GETFONT := 0x31
, IMAGE_BITMAP := 0x0 , BITSPIXEL := 0xC
, RCBUTTONS := BS_CHECKBOX | BS_RADIOBUTTON | BS_AUTORADIOBUTTON
, BCM_SETIMAGELIST := 0x1602
, BUTTON_IMAGELIST_ALIGN_LEFT := 0
, BUTTON_IMAGELIST_ALIGN_RIGHT := 1
, BUTTON_IMAGELIST_ALIGN_CENTER := 4
; Options
Static OptionKeys := ["TC", "BC", "3D", "G"]
; Defaults
Static Defaults := {TC: "000000", BC: "000000", 3D: 0, G: 0}
; -------------------------------------------------------------------------------------------------------------------
ErrorLevel := ""
; -------------------------------------------------------------------------------------------------------------------
; Check the availability of Gdiplus.dll
GDIPDll := DllCall("Kernel32.dll\LoadLibrary", "Str", "Gdiplus.dll", "Ptr")
VarSetCapacity(SI, 24, 0)
Numput(1, SI)
DllCall("Gdiplus.dll\GdiplusStartup", "PtrP", GDIPToken, "Ptr", &SI, "Ptr", 0)
If (!GDIPToken) {
ErrorLevel := "GDIPlus could not be started!`n`nImageButton won't work!"
Return False
}
; -------------------------------------------------------------------------------------------------------------------
; Check HWND
If !(DllCall("User32.dll\IsWindow", "Ptr", HWND)) {
GoSub, CreateImageButton_GDIPShutdown
ErrorLevel := "Invalid parameter HWND!"
Return False
}
; -------------------------------------------------------------------------------------------------------------------
; Check Options
If !(IsObject(Options)) || (Options.MinIndex() = "") || (Options.MinIndex() > 1) || (Options.MaxIndex() > 6) {
GoSub, CreateImageButton_GDIPShutdown
ErrorLevel := "Invalid parameter Options!"
Return False
}
; -------------------------------------------------------------------------------------------------------------------
; Check Margins
Margins := SubStr(Margins, 1, 1)
If (Margins = "") || !(Instr("01234", Margins))
Margins := 0
; -------------------------------------------------------------------------------------------------------------------
; Get and check control's class and styles
WinGetClass, BtnClass, ahk_id %HWND%
ControlGet, BtnStyle, Style, , , ahk_id %HWND%
If (BtnClass != "Button") || ((BtnStyle & 0xF ^ BS_GROUPBOX) = 0) || ((BtnStyle & RCBUTTONS) > 1) {
GoSub, CreateImageButton_GDIPShutdown
ErrorLevel := "You can use ImageButton only for PushButtons!"
Return False
}
; -------------------------------------------------------------------------------------------------------------------
; Get the button's font
GDIPFont := 0
DC := DllCall("User32.dll\GetDC", "Ptr", HWND, "Ptr")
BPP := DllCall("Gdi32.dll\GetDeviceCaps", "Ptr", DC, "Int", BITSPIXEL)
HFONT := DllCall("User32.dll\SendMessage", "Ptr", HWND, "UInt", WM_GETFONT, "Ptr", 0, "Ptr", 0, "Ptr")
DllCall("Gdi32.dll\SelectObject", "Ptr", DC, "Ptr", HFONT)
DllCall("Gdiplus.dll\GdipCreateFontFromDC", "Ptr", DC, "PtrP", GDIPFont)
DllCall("User32.dll\ReleaseDC", "Ptr", HWND, "Ptr", DC)
If !(GDIPFont) {
GoSub, CreateImageButton_GDIPShutdown
ErrorLevel := "Couldn't get button's font!"
Return False
}
; -------------------------------------------------------------------------------------------------------------------
; Get the button's RECT
VarSetCapacity(RECT, 16, 0)
If !(DllCall("User32.dll\GetClientRect", "Ptr", HWND, "Ptr", &RECT)) {
GoSub, CreateImageButton_GDIPShutdown
ErrorLevel := "Couldn't get button's rectangle!"
Return False
}
W := NumGet(RECT, 8, "Int") - (Margins * 2)
H := NumGet(RECT, 12, "Int") - (Margins * 2)
; -------------------------------------------------------------------------------------------------------------------
; Get the button's caption
BtnCaption := ""
Len := DllCall("User32.dll\GetWindowTextLength", "Ptr", HWND) + 1
If (Len > 1) { ; Button has a caption
VarSetCapacity(BtnCaption, Len * (A_IsUnicode ? 2 : 1), 0)
If !(DllCall("User32.dll\GetWindowText", "Ptr", HWND, "Str", BtnCaption, "Int", Len)) {
GoSub, CreateImageButton_GDIPShutdown
ErrorLevel := "Couldn't get button's caption!"
Return False
}
VarSetCapacity(BtnCaption, -1)
}
; -------------------------------------------------------------------------------------------------------------------
; Create the BitMap(s)
BitMaps := []
While (A_Index <= Options.MaxIndex()) {
If !(Options.HasKey(A_Index))
Continue
Option := Options[A_Index]
; Check mandatory keys
If !(Option.HasKey("BC")) {
GoSub, CreateImageButton_FreeBitmaps
GoSub, CreateImageButton_GDIPShutdown
ErrorLevel := "Missing option BC in Options[" . A_Index . "]!"
Return False
}
; Check for defaults
For Each, K In Defaults {
If !(Option.HasKey(K)) || (Option[K] = "")
Option[K] := Defaults[K]
}
; Check options
BitMap := ""
GC := SubStr(Option.G, 1, 1)
If !InStr("01", GC)
GC := Defaults.G
3D := SubStr(Option.3D, 1, 1)
If !InStr("01239", 3D)
3D := Defaults.3D
If (3D < 4) {
BkgColor := Option.BC
If InStr(BkgColor, "|") {
StringSplit, BkgColor, BkgColor, |
} Else {
BkgColor1 := Option.3D = 0 ? BkgColor : Defaults.BC
BkgColor2 := BkgColor
}
If HTML.HasKey(BkgColor1)
BkgColor1 := HTML[BkgColor1]
If HTML.HasKey(BkgColor2)
BkgColor2 := HTML[BkgColor2]
} Else {
Image := Option.BC
}
TxtColor := Option.TC
If HTML.HasKey(TxtColor)
TxtColor := HTML[TxtColor]
; ----------------------------------------------------------------------------------------------------------------
; Create a GDI+ bitmap
DllCall("Gdiplus.dll\GdipCreateBitmapFromScan0", "Int", W, "Int", H, "Int", 0
, "UInt", 0x26200A, "Ptr", 0, "PtrP", PBITMAP)
; Get the pointer to it's graphics
DllCall("Gdiplus.dll\GdipGetImageGraphicsContext", "Ptr", PBITMAP, "PtrP", PGRAPHICS)
; Set SmoothingMode to system default
DllCall("Gdiplus.dll\GdipSetSmoothingMode", "Ptr", PGRAPHICS, "UInt", 0)
If (3D < 4) { ; Create a BitMap
; Create a PathGradientBrush
VarSetCapacity(POINTS, 4 * 8, 0)
NumPut(W - 1, POINTS, 8, "UInt"), NumPut(W - 1, POINTS, 16, "UInt")
NumPut(H - 1, POINTS, 20, "UInt"), NumPut(H - 1, POINTS, 28, "UInt")
DllCall("Gdiplus.dll\GdipCreatePathGradientI", "Ptr", &POINTS, "Int", 4, "Int", 0, "PtrP", PBRUSH)
; Start and target colors
Color1 := "0xFF" . BkgColor1
Color2 := "0xFF" . BkgColor2
; Set the PresetBlend
VarSetCapacity(COLORS, 12, 0)
NumPut(Color1, COLORS, 0, "UInt"), NumPut(Color2, COLORS, 4, "UInt")
VarSetCapacity(RELINT, 12, 0)
NumPut(0.00, RELINT, 0, "Float"), NumPut(1.00, RELINT, 4, "Float")
DllCall("Gdiplus.dll\GdipSetPathGradientPresetBlend", "Ptr", PBRUSH, "Ptr", &COLORS, "Ptr", &RELINT, "Int", 2)
; Set the FocusScales
DH := H / 2
XScale := (3D = 1 ? (W - DH) / W : 3D = 2 ? 1 : 0)
YScale := (3D = 1 ? (H - DH) / H : 3D = 3 ? 1 : 0)
DllCall("Gdiplus.dll\GdipSetPathGradientFocusScales", "Ptr", PBRUSH, "Float", XScale, "Float", YScale)
; Set the GammaCorrection
DllCall("Gdiplus.dll\GdipSetPathGradientGammaCorrection", "Ptr", PBRUSH, "Int", GC)
; Fill button's rectangle
DllCall("Gdiplus.dll\GdipFillRectangleI", "Ptr", PGRAPHICS, "Ptr", PBRUSH, "Int", 0, "Int", 0
, "Int", W, "Int", H)
; Free the brush
DllCall("Gdiplus.dll\GdipDeleteBrush", "Ptr", PBRUSH)
} Else { ; Create a bitmap from HBITMAP or file
If (Image + 0)
DllCall("Gdiplus.dll\GdipCreateBitmapFromHBITMAP", "Ptr", Image, "Ptr", 0, "PtrP", PBM)
Else
DllCall("Gdiplus.dll\GdipCreateBitmapFromFile", "WStr", Image, "PtrP", PBM)
; Draw the bitmap
DllCall("Gdiplus.dll\GdipDrawImageRectI", "Ptr", PGRAPHICS, "Ptr", PBM, "Int", 0, "Int", 0
, "Int", W, "Int", H)
; Free the bitmap
DllCall("Gdiplus.dll\GdipDisposeImage", "Ptr", PBM)
}
; ----------------------------------------------------------------------------------------------------------------
; Draw the caption
If (BtnCaption) {
; Create a StringFormat object
DllCall("Gdiplus.dll\GdipCreateStringFormat", "Int", 0x5404, "UInt", 0, "PtrP", HFORMAT)
; Text color
DllCall("Gdiplus.dll\GdipCreateSolidFill", "UInt", "0xFF" . TxtColor, "PtrP", PBRUSH)
; Horizontal alignment
HALIGN := (BtnStyle & BS_CENTER) = BS_CENTER ? SA_CENTER
: (BtnStyle & BS_CENTER) = BS_RIGHT ? SA_RIGHT
: (BtnStyle & BS_CENTER) = BS_Left ? SA_LEFT
: SA_CENTER
DllCall("Gdiplus.dll\GdipSetStringFormatAlign", "Ptr", HFORMAT, "Int", HALIGN)
; Vertical alignment
VALIGN := (BtnStyle & BS_VCENTER) = BS_TOP ? 0
: (BtnStyle & BS_VCENTER) = BS_BOTTOM ? 2
: 1
DllCall("Gdiplus.dll\GdipSetStringFormatLineAlign", "Ptr", HFORMAT, "Int", VALIGN)
; Set render quality to system default
DllCall("Gdiplus.dll\GdipSetTextRenderingHint", "Ptr", PGRAPHICS, "Int", 0)
; Set the text's rectangle
NumPut(0.0, RECT, 0, "Float")
NumPut(0.0, RECT, 4, "Float")
NumPut(W, RECT, 8, "Float")
NumPut(H, RECT, 12, "Float")
; Draw the text
DllCall("Gdiplus.dll\GdipDrawString", "Ptr", PGRAPHICS, "WStr", BtnCaption, "Int", -1
, "Ptr", GDIPFont, "Ptr", &RECT, "Ptr", HFORMAT, "Ptr", PBRUSH)
}
; Create a HBITMAP handle from the bitmap
DllCall("Gdiplus.dll\GdipCreateHBITMAPFromBitmap", "Ptr", PBITMAP, "PtrP", HBITMAP, "UInt", 0X00FFFFFF)
; Free resources
DllCall("Gdiplus.dll\GdipDisposeImage", "Ptr", PBITMAP)
DllCall("Gdiplus.dll\GdipDeleteBrush", "Ptr", PBRUSH)
DllCall("Gdiplus.dll\GdipDeleteStringFormat", "Ptr", HFORMAT)
DllCall("Gdiplus.dll\GdipDeleteGraphics", "Ptr", PGRAPHICS)
BitMaps[A_Index] := HBITMAP
}
; Now free the font object
DllCall("Gdiplus.dll\GdipDeleteFont", "Ptr", GDIPFont)
; -------------------------------------------------------------------------------------------------------------------
; Create the ImageList
HIL := DllCall("Comctl32.dll\ImageList_Create", "UInt", W, "UInt", H, "UInt", BPP, "Int", 6, "Int", 0, "Ptr")
Loop, % (BitMaps.MaxIndex() > 1 ? 6 : 1) {
HBITMAP := BitMaps.HasKey(A_Index) ? BitMaps[A_Index] : BitMaps[1]
DllCall("Comctl32.dll\ImageList_Add", "Ptr", HIL, "Ptr", HBITMAP, "Ptr", 0)
}
; Create a BUTTON_IMAGELIST structure
VarSetCapacity(BIL, 20 + A_PtrSize, 0)
NumPut(HIL, BIL, 0, "Ptr")
Numput(BUTTON_IMAGELIST_ALIGN_CENTER, BIL, A_PtrSize + 16, "UInt")
; Hide buttons's caption
GuiControl, , %HWND% ; WinXP
GuiControl, +%BS_BITMAP%, %HWND%
; Assign the ImageList to the button
SendMessage, BCM_SETIMAGELIST, 0, 0, , ahk_id %HWND%
SendMessage, BCM_SETIMAGELIST, 0, &BIL, , ahk_id %HWND%
; Free the bitmaps
GoSub, CreateImageButton_FreeBitmaps
; -------------------------------------------------------------------------------------------------------------------
; All done successfully
GoSub, CreateImageButton_GDIPShutdown
Return True
; -------------------------------------------------------------------------------------------------------------------
; Free BitMaps
CreateImageButton_FreeBitmaps:
For I, HBITMAP In BitMaps {
DllCall("Gdi32.dll\DeleteObject", "Ptr", HBITMAP)
}
Return
; -------------------------------------------------------------------------------------------------------------------
; Shutdown GDIPlus
CreateImageButton_GDIPShutdown:
DllCall("Gdiplus.dll\GdiplusShutdown", "Ptr", GDIPToken)
DllCall("Kernel32.dll\FreeLibrary", "Ptr", GDIPDll)
Return
}Sample script:
#NoEnv
#Include CreateImageButton.ahk
; ----------------------------------------------------------------------------------------------------------------------
Gui, Margin, 50, 20
Gui, Font, s10
; Common button
Gui, Add, Button, w200, Button 0
; Image button with different images for states normal and hot
Gui, Add, Button, vBT1 w200 hwndHBT1, Button 1
BT1Options := [{BC: "600000|D00000", TC: "White", 3D: 1, G: 0}]
BT1Options[2] := {BC: "800000|F00000", TC: "Lime", 3D: 1, G: 1}
If !CreateImageButton(HBT1, BT1Options)
MsgBox, %ErrorLevel%
; Image button with margins and different images for states normal, hot, and pressed
Gui, Add, Button, vBT2 w200 Default hwndHBT2, Button 2
BT2Options := [{BC: "404040|C0C0C0", TC: "Blue", 3D: 2}]
BT2Options[2] := {BC: "606060|F0F0F0", TC: "Green", 3D: 2}
BT2Options[3] := {BC: "404040|C0C0C0", TC: "Red", 3D: 2}
If !CreateImageButton(HBT2, BT2Options, 3)
MsgBox, %ErrorLevel%
; Image button with different images for states normal, hot, and disabled
Gui, Add, Button, vBT3 w200 Disabled hwndHBT3, Button 3
BT3Options := [{BC: "404040|C0C0C0", TC: "Yellow", 3D: 3, G: 0}]
BT3Options[2] := {BC : "606060|F0F0F0", TC: "606000", 3D: 3, G: 0}
BT3Options[4] := {BC : "606060|A0A0A0", TC: "606000", 3D: 1, G: 0}
If !CreateImageButton(HBT3, BT3Options)
MsgBox, %ErrorLevel%
Gui, Font
Gui, Add, CheckBox, xp y+0 w200 gCheck vCheckBox, Enable!
; Image button with different pictures for states normal and hot
Gui, Add, Button, vBT4 w200 h30 hwndHBT4
BT4Options := [{BC: "PIC1.jpg", 3D: 9, G: 0}]
BT4Options[2] := {BC: "PIC2.jpg", 3D: 9, G: 1}
If !CreateImageButton(HBT4, BT4Options)
MsgBox, %ErrorLevel%
GuiControl, Focus, BT2
Gui, Show, , Image Buttons
Return
; ----------------------------------------------------------------------------------------------------------------------
GuiClose:
GuiEscape:
ExitApp
Check:
GuiControlGet, CheckBox
GuiControl, Enable%CheckBox%, BT3
GuiControl, Text, CheckBox, % (CheckBox ? "Disable!" : "Enable!")
ReturnUpdate on 2012-04-03:Fixed caption issue on WinXP.
Download all files: :arrow: CreateImageButton.zip






