I am in a state of near-celebration! I have working auto-generated GUI image text buttons with rollover effect... finally!
I added a GDI+ call to get the bitmap's dimensions after it is loaded, and used that in the Gui, Add, Picture command.
One side effect is it seems the first button I hover over does not get a rollover image, I have to move the mouse to another button, then that and all future rollovers work until the mouse leaves and re-enters the window. So the first button rolled over after the pointer enters the window doesn't seem to trigger the rollover image.
It might not be pretty, but here's how I finally got it figured out.
Function to create button:
Code:
SW_AddTextButton(pVar, pLabel="", pName = "", pSize="", pBg="", pOptions = "", pSteamWin = "") {
; Adds a Steam-like graphical button to the specified Steam window with a graphical text label on it
local thisGuiNum, thisImgDir, thisHandle, thisBitmap
If Not pSteamWin {
If SteamWin
pSteamWin := SteamWin
Else Return 0 ; Current SteamWin unknown
}
If Not pName
pName := "OK" ; Default to an OK button
If Not pBg
pBg := "Bg"
; Calculate button size required, if not specified
If Not pSize {
thisSize := GetTextSize(pName, "S8", "Tahoma")
pSize := (thisSize > 53) ? 3 : 2
}
If Not pLabel
pLabel := pVar ; If no label is specified, use the variable name as a label
thisGuiNum := SteamWin%pSteamWin%GuiNum
thisImgDir := SteamWin%pSteamWin%ImgDir
; Check if button already generated
FileCreateDir,%thisImgDir%\tmp\btn
thisFile1 := thisImgDir . "\tmp\btn\" . pName . "_" . pSize . ".bmp"
If Not FileExist(thisFile1) ; generate the button
TextToImage(thisImgDir . "\btn\Button_" . pSize . "_" . pBg . ".png",pName,thisFile1,"XP=12 YP=7 Height=8.5 Align=Left|Top Weight=100 TextColour=FFFFFF Quality=3", "Tahoma")
; Check if rollover already generated
thisFile2 := thisImgDir . "\tmp\btn\" . pName . "_" . pSize . "_ro.bmp"
If Not FileExist(thisFile2) ; generate the button
TextToImage(thisImgDir . "\btn\Button_" . pSize . "_" . pBg . ".png",pName,thisFile2,"XP=12 YP=7 Height=8.5 Align=Left|Top Weight=100 TextColour=C4B550 Quality=3", "Tahoma")
If thisGuiNum
Gui, %thisGuiNum%:Default ; If there's a GUI num, make it the default
hGdiPlus := DllCall("LoadLibrary", "Str", "gdiplus.dll")
VarSetCapacity(si, 16, 0), si := Chr(1)
DllCall("gdiplus\GdiplusStartup", "UintP", pToken, "UInt", &si, "Uint", 0)
Loop, 2 { ; Load button and its rollover
VarSetCapacity(wFile%A_Index%, StrLen(thisFile%A_Index%)*2+2)
DllCall("kernel32\MultiByteToWideChar", "UInt", 0, "UInt", 0, "Str", thisFile%A_Index%, "Int", -1, "UInt", &wFile%A_Index%, "Int", VarSetCapacity(wFile%A_Index%)//2)
DllCall("gdiplus\GdipCreateBitmapFromFile", "UInt", &wFile%A_Index%, "UIntP", pBitmap%A_Index%)
If pBitmap%A_Index% {
DllCall("gdiplus\GdipCreateHBITMAPFromBitmap", "UInt", pBitmap%A_Index%, "UIntP", hBM%A_Index%, "UInt", 0)
DllCall("GDIplus.dll\GdipGetImageDimension", "UInt", pBitmap%A_Index%, "Float *", imageWidth%A_Index%, "Float *", imageHeight%A_Index%)
hBM%A_Index%W := Floor(imageWidth%A_Index%)
hBM%A_Index%H := Floor(imageHeight%A_Index%)
DllCall("gdiplus\GdipDisposeImage", "Uint", pBitmap%A_Index%)
}
}
DllCall("gdiplus\GdiplusShutdown" , "UInt", pToken)
DllCall("FreeLibrary", "UInt", hGdiPlus)
Gui, Add, Picture, v%pVar% %pOptions% hwnd%pVar%_hwnd w%hBM1W% h%hBM1H% 0xE g%pLabel%
SendMessage, 0x172, 0, hBM1,,% "ahk_id " . %pVar%_hwnd ; STM_SETIMAGE
If ErrorLevel ; delete previous image
DllCall("DeleteObject", "uint", ErrorLevel)
%pVar%b1 := hBM1
%pVar%b1_ro := hBM2
%pVar%_bW := hBM1W
%pVar%_bH := hBM1H
%pVar%_bO := pOptions
%pVar%_bG := pLabel
ActiveTextButtons .= pVar . "|"
;Gui, Add, Picture, w%thisW% h%thisH% g%pLabel% %pOptions% v%pVar%, %thisFile2%
Return 1
}
My events (covering both my normal buttons and my text buttons):
Code:
OnMessage(0x200, "BtnMouseMove")
OnMessage(0x2A3, "BtnMouseLeave")
OnMessage(0x202, "BtnMouseLeave")
BtnMouseLeave(wParam, lParam, msg, hwnd) {
Global
theseButtons := ActiveButtons . "|" . ActiveDockButtons
Loop, Parse, theseButtons,|
If (hwnd = %A_LoopField%_hwnd) {
AddGraphicButton(A_LoopField, %A_LoopField%b1, %A_LoopField%_bO . " w" . %A_LoopField%_bW . " h" . %A_LoopField%_bH . " g" . %A_LoopField%_bG,%A_LoopField%_bH,%A_LoopField%_bW)
}
Loop, Parse, ActiveTextButtons,|
If (hwnd = %A_LoopField%_hwnd) {
SendMessage, 0x172, 0,% %A_LoopField%b1,, ahk_id %hwnd% ; STM_SETIMAGE
}
}
BtnMouseMove(wParam, lParam, msg, hwnd) {
Global
Static _LastButtonData = true
theseButtons := ActiveButtons . "|" . ActiveDockButtons
btnType := 0
Loop, Parse, theseButtons,|
{ If (hwnd = %A_LoopField%_hwnd and _LastButtonData != %A_LoopField%_hwnd) {
AddGraphicButton(A_LoopField, %A_LoopField%b1_ro, %A_LoopField%_bO . " w" . %A_LoopField%_bW . " h" . %A_LoopField%_bH . " g" . %A_LoopField%_bG,%A_LoopField%_bH,%A_LoopField%_bW)
}
}
Loop, Parse, ActiveTextButtons,|
{ If (hwnd = %A_LoopField%_hwnd) {
If (_LastTextButtonData != %A_LoopField%_hwnd) {
SendMessage, 0x172, 0,% %A_LoopField%b1_ro,, ahk_id %hwnd% ; STM_SETIMAGE
ThisTextButtonVar := A_LoopField
btnType := 1
}
}
}
If (hwnd != _LastTextButtonData) {
SendMessage, 0x172, 0,% %_LastTextButtonVar%b1,, ahk_id %_LastTextButtonData% ; STM_SETIMAGE
}
If btnType {
_LastTextButtonData := hwnd
_LastTextButtonVar := ThisTextButtonVar
} Else
_LastButtonData := hwnd
Return
}
Thank you so much tic and lexikos for helping me get to this point. I'm very happy that I can now replace all of my buttons with these much nicer methods!