[Class] ImageButton - 1.5.00.00 - 20201230

Post your working scripts, libraries and tools for AHK v1.1 and older
User avatar
boiler
Posts: 16927
Joined: 21 Dec 2014, 02:44

Re: [Class] ImageButton - 1.5.00.00 - 20201230

Post by boiler » 27 Dec 2022, 06:21

So I would say that the solution to the problem would be to just enter the text in reverse order rather than applying the style. You could make use of a function the reverses the order of the characters, like the one below by jNizM so you don’t have to type them backwards.

Code: Select all

StringReverse(str)
{
    static rev := A_IsUnicode ? "_wcsrev" : "_strrev"
    DllCall("msvcrt.dll\" rev, "Ptr", &str) ; "CDECL"
    return str
}

User avatar
HiSoKa
Posts: 480
Joined: 27 Jan 2020, 15:43

Re: [Class] ImageButton - 1.5.00.00 - 20201230

Post by HiSoKa » 27 Dec 2022, 08:56

Thanks you guys for the help :salute:

magicshow
Posts: 67
Joined: 14 Oct 2022, 11:38

Re: [Class] ImageButton - 1.5.00.00 - 20201230

Post by magicshow » 03 Jan 2023, 13:19

This button is without background on purpose.
Is this possible to get rid of the outline's white pixels ?
thks
Attachments
wl.png
wl.png (19.72 KiB) Viewed 1844 times

just me
Posts: 9453
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: [Class] ImageButton - 1.5.00.00 - 20201230

Post by just me » 04 Jan 2023, 05:06

Which options do you use to create this button?

magicshow
Posts: 67
Joined: 14 Oct 2022, 11:38

Re: [Class] ImageButton - 1.5.00.00 - 20201230

Post by magicshow » 04 Jan 2023, 15:03

just me wrote:
04 Jan 2023, 05:06
Which options do you use to create this button?

Code: Select all

gui , color,  f0f0f0
gui, +lastfound
winset, transcolor, f0f0f0

Gui, Add, Button, w100 h100 x257 y267 hWndhBtn7777 G%hold_label_1% vhold_label_1v,  %hold_name_bb%

IBBtnStyles := [ [0, 0xC3FAC3, ,0xD43FFF, 25, , 0xD43FAA, 2]           ; normal
			   , [0, 0xd7ffd7, ,, 0, , , 1]     
			   , [0, 0xc3fae8, , , 0, , , 1]            
			   , [1, 1, ,1, 1, 1, 1, 1] ]					
ImageButton.Create(hBtn7777, IBBtnStyles*)
Something like that. The problem is ahk only allow you to set the transcolor for once while the buttons 's color can be different...

just me
Posts: 9453
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: [Class] ImageButton - 1.5.00.00 - 20201230

Post by just me » 05 Jan 2023, 02:04

It's related to winset, transcolor, f0f0f0. The class cannot do anything to prevent this.

robodesign
Posts: 934
Joined: 30 Sep 2017, 03:59
Location: Romania
Contact:

Re: [Class] ImageButton - 1.5.00.00 - 20201230

Post by robodesign » 31 Jan 2023, 11:53

Why do the accelerator keys do not work anymore?
-------------------------
KeyPress OSD v4: GitHub or forum. (presentation video)
Quick Picto Viewer: GitHub or forum.
AHK GDI+ expanded / compilation library (on GitHub)
My home page.

robodesign
Posts: 934
Joined: 30 Sep 2017, 03:59
Location: Romania
Contact:

Re: [Class] ImageButton - 1.5.00.00 - 20201230

Post by robodesign » 01 Feb 2023, 02:50

I fixed the library:

Code: Select all

; ======================================================================================================================
; Namespace:         ImageButton
; Function:          Create images and assign them to pushbuttons.
; Tested with:       AHK 1.1.33.02 (A32/U32/U64)
; Tested on:         Win 10 (x64)
; Change history:    1.6.00.00/2023-02-02/marius-sucan - It now allows to use & to underline the accelerator key for the button, and they are no longer broken, they work.. It breaks winxp compatiblity.
;                                                        Changed all PTR and PtrP to Uptr and Uptr*.

;                    1.5.00.00/2020-12-16/just me - increased script performance, added support for icons (HICON)
;                    1.4.00.00/2014-06-07/just me - fixed bug for button caption = "0", "000", etc.
;                    1.3.00.00/2014-02-28/just me - added support for ARGB colors
;                    1.2.00.00/2014-02-23/just me - added borders
;                    1.1.00.00/2013-12-26/just me - added rounded and bicolored buttons       
;                    1.0.00.00/2013-12-21/just me - initial release
; How to use:
;     1. Create a push button (e.g. "Gui, Add, Button, vMyButton hwndHwndButton, Caption") using the 'Hwnd' option
;        to get its HWND.
;     2. Call ImageButton.Create() passing two parameters:
;        HWND        -  Button's HWND.
;        Options*    -  variadic array containing up to 6 option arrays (see below).
;        ---------------------------------------------------------------------------------------------------------------
;        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):
;            PBS_NORMAL    = 1
;            PBS_HOT       = 2
;            PBS_PRESSED   = 3
;            PBS_DISABLED  = 4
;            PBS_DEFAULTED = 5
;            PBS_STYLUSHOT = 6 <- used only on tablet computers (that's false for Windows Vista and 7, see below)
;        If you don't want the button to be 'animated' on themed GUIs, just pass one option object with index 1.
;        On Windows Vista and 7 themed bottons are 'animated' using the images of states 5 and 6 after clicked.
;        ---------------------------------------------------------------------------------------------------------------
;        Each option array may contain the following values:
;           Index Value
;           1     Mode        mandatory:
;                             0  -  unicolored or bitmap
;                             1  -  vertical bicolored
;                             2  -  horizontal bicolored
;                             3  -  vertical gradient
;                             4  -  horizontal gradient
;                             5  -  vertical gradient using StartColor at both borders and TargetColor at the center
;                             6  -  horizontal gradient using StartColor at both borders and TargetColor at the center
;                             7  -  'raised' style
;           2     StartColor  mandatory for Option[1], higher indices will inherit the value of Option[1], if omitted:
;                             -  ARGB integer value (0xAARRGGBB) or HTML color name ("Red").
;                             -  Path of an image file or HBITMAP handle for mode 0.
;           3     TargetColor mandatory for Option[1] if Mode > 0. Higher indcices will inherit the color of Option[1],
;                             if omitted:
;                             -  ARGB integer value (0xAARRGGBB) or HTML color name ("Red").
;                             -  String "HICON" if StartColor contains a HICON handle.
;           4     TextColor   optional, if omitted, the default text color will be used for Option[1], higher indices 
;                             will inherit the color of Option[1]:
;                             -  ARGB integer value (0xAARRGGBB) or HTML color name ("Red").
;                                Default: 0xFF000000 (black)
;           5     Rounded     optional:
;                             -  Radius of the rounded corners in pixel; the letters 'H' and 'W' may be specified
;                                also to use the half of the button's height or width respectively.
;                                Default: 0 - not rounded
;           6     GuiColor    optional, needed for rounded buttons if you've changed the GUI background color:
;                             -  RGB integer value (0xRRGGBB) or HTML color name ("Red").
;                                Default: AHK default GUI background color
;           7     BorderColor optional, ignored for modes 0 (bitmap) and 7, color of the border:
;                             -  RGB integer value (0xRRGGBB) or HTML color name ("Red").
;           8     BorderWidth optional, ignored for modes 0 (bitmap) and 7, width of the border in pixels:
;                             -  Default: 1
;        ---------------------------------------------------------------------------------------------------------------
;        If the the button has a caption it will be drawn above the bitmap.
; 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
; ======================================================================================================================
; 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.
; ======================================================================================================================
; ======================================================================================================================
; CLASS ImageButton()
; ======================================================================================================================
Class ImageButton {
   ; ===================================================================================================================
   ; PUBLIC PROPERTIES =================================================================================================
   ; ===================================================================================================================
   Static DefGuiColor  := ""        ; default GUI color                             (read/write)
   Static DefTxtColor := "Black"    ; default caption color                         (read/write)
   Static LastError := ""           ; will contain the last error message, if any   (readonly)
   ; ===================================================================================================================
   ; PRIVATE PROPERTIES ================================================================================================
   ; ===================================================================================================================
   Static BitMaps := []
   Static MaxOptions := 8
   ; HTML colors
   Static HTML := {BLACK: 0x000000, GRAY: 0x808080, SILVER: 0xC0C0C0, WHITE: 0xFFFFFF, MAROON: 0x800000
                 , PURPLE: 0x800080, FUCHSIA: 0xFF00FF, RED: 0xFF0000, GREEN: 0x008000, OLIVE: 0x808000
                 , YELLOW: 0xFFFF00, LIME: 0x00FF00, NAVY: 0x000080, TEAL: 0x008080, AQUA: 0x00FFFF, BLUE: 0x0000FF}
   ; Initialize
   Static ClassInit := ImageButton.InitClass()
   ; ===================================================================================================================
   ; PRIVATE METHODS ===================================================================================================
   ; ===================================================================================================================
   __New(P*) {
      Return False
   }
   ; ===================================================================================================================
   InitClass() {
      ; ----------------------------------------------------------------------------------------------------------------
      ; Get AHK's default GUI background color
      GuiColor := DllCall("User32.dll\GetSysColor", "Int", 15, "UInt") ; COLOR_3DFACE is used by AHK as default
      This.DefGuiColor := ((GuiColor >> 16) & 0xFF) | (GuiColor & 0x00FF00) | ((GuiColor & 0xFF) << 16)
      Return True
   }
   ; ===================================================================================================================
   BitmapOrIcon(O2, O3) {
      ; OBJ_BITMAP = 7
      Return (This.IsInt(O2) && (O3 = "HICON")) || (DllCall("GetObjectType", "UPtr", O2, "UInt") = 7) || FileExist(O2)
   }
   ; ===================================================================================================================
   FreeBitmaps() {
      For I, HBITMAP In This.BitMaps
         DllCall("Gdi32.dll\DeleteObject", "UPtr", HBITMAP)
      This.BitMaps := []
   }
   ; ===================================================================================================================
   GetARGB(RGB) {
      ARGB := This.HTML.HasKey(RGB) ? This.HTML[RGB] : RGB
      Return (ARGB & 0xFF000000) = 0 ? 0xFF000000 | ARGB : ARGB
   }
   ; ===================================================================================================================
   IsInt(Val) {
      If Val Is Integer
         Return True
      Return False
   }
   ; ===================================================================================================================
   PathAddRectangle(Path, X, Y, W, H) {
      Return DllCall("Gdiplus.dll\GdipAddPathRectangle", "UPtr", Path, "Float", X, "Float", Y, "Float", W, "Float", H)
   }
   ; ===================================================================================================================
   PathAddRoundedRect(Path, X1, Y1, X2, Y2, R) {
      D := (R * 2), X2 -= D, Y2 -= D
      DllCall("Gdiplus.dll\GdipAddPathArc"
            , "UPtr", Path, "Float", X1, "Float", Y1, "Float", D, "Float", D, "Float", 180, "Float", 90)
      DllCall("Gdiplus.dll\GdipAddPathArc"
            , "UPtr", Path, "Float", X2, "Float", Y1, "Float", D, "Float", D, "Float", 270, "Float", 90)
      DllCall("Gdiplus.dll\GdipAddPathArc"
            , "UPtr", Path, "Float", X2, "Float", Y2, "Float", D, "Float", D, "Float", 0, "Float", 90)
      DllCall("Gdiplus.dll\GdipAddPathArc"
            , "UPtr", Path, "Float", X1, "Float", Y2, "Float", D, "Float", D, "Float", 90, "Float", 90)
      Return DllCall("Gdiplus.dll\GdipClosePathFigure", "UPtr", Path)
   }
   ; ===================================================================================================================
   SetRect(ByRef Rect, X1, Y1, X2, Y2) {
      VarSetCapacity(Rect, 16, 0)
      NumPut(X1, Rect, 0, "Int"), NumPut(Y1, Rect, 4, "Int")
      NumPut(X2, Rect, 8, "Int"), NumPut(Y2, Rect, 12, "Int")
      Return True
   }
   ; ===================================================================================================================
   SetRectF(ByRef Rect, X, Y, W, H) {
      VarSetCapacity(Rect, 16, 0)
      NumPut(X, Rect, 0, "Float"), NumPut(Y, Rect, 4, "Float")
      NumPut(W, Rect, 8, "Float"), NumPut(H, Rect, 12, "Float")
      Return True
   }
   ; ===================================================================================================================
   SetError(Msg) {
      If (This.Bitmap)
         DllCall("Gdiplus.dll\GdipDisposeImage", "UPtr", This.Bitmap)
      If (This.Graphics)
         DllCall("Gdiplus.dll\GdipDeleteGraphics", "UPtr", This.Graphics)
      If (This.Font)
         DllCall("Gdiplus.dll\GdipDeleteFont", "UPtr", This.Font)
      This.Delete("Bitmap")
      This.Delete("Graphics")
      This.Delete("Font")
      This.FreeBitmaps()
      ; This.GdiplusShutdown()
      This.LastError := Msg
      Return False
   }
   ; ===================================================================================================================
   ; PUBLIC METHODS ====================================================================================================
   ; ===================================================================================================================
   Create(HWND, Options*) {
      ; Windows constants
      Static BCM_GETIMAGELIST := 0x1603, BCM_SETIMAGELIST := 0x1602
           , BS_CHECKBOX := 0x02, BS_RADIOBUTTON := 0x04, BS_GROUPBOX := 0x07, BS_AUTORADIOBUTTON := 0x09
           , BS_LEFT := 0x0100, BS_RIGHT := 0x0200, BS_CENTER := 0x0300, BS_TOP := 0x0400, BS_BOTTOM := 0x0800
           , BS_VCENTER := 0x0C00, BS_BITMAP := 0x0080
           , BUTTON_IMAGELIST_ALIGN_LEFT := 0, BUTTON_IMAGELIST_ALIGN_RIGHT := 1, BUTTON_IMAGELIST_ALIGN_CENTER := 4
           , ILC_COLOR32 := 0x20
           , OBJ_BITMAP := 7
           , RCBUTTONS := BS_CHECKBOX | BS_RADIOBUTTON | BS_AUTORADIOBUTTON
           , SA_LEFT := 0x00, SA_CENTER := 0x01, SA_RIGHT := 0x02
           , WM_GETFONT := 0x31
      ; ----------------------------------------------------------------------------------------------------------------
      This.LastError := ""
      HBITMAP := HFORMAT := PBITMAP := PBRUSH := PFONT := PPATH := 0
      ; ----------------------------------------------------------------------------------------------------------------
      ; Check HWND
      If !DllCall("User32.dll\IsWindow", "UPtr", HWND)
         Return This.SetError("Invalid parameter HWND!")
      ; ----------------------------------------------------------------------------------------------------------------
      ; Check Options
      If !(IsObject(Options)) || (Options.MinIndex() <> 1) || (Options.MaxIndex() > This.MaxOptions)
         Return This.SetError("Invalid parameter Options!")
      ; ----------------------------------------------------------------------------------------------------------------
      ; 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)
         Return This.SetError("The control must be a pushbutton!")
      ; ----------------------------------------------------------------------------------------------------------------
      ; Get the button's font
      HFONT := DllCall("User32.dll\SendMessage", "UPtr", HWND, "UInt", WM_GETFONT, "UPtr", 0, "UPtr", 0, "Ptr")
      DC := DllCall("User32.dll\GetDC", "UPtr", HWND, "Ptr")
      DllCall("Gdi32.dll\SelectObject", "UPtr", DC, "UPtr", HFONT)
      DllCall("Gdiplus.dll\GdipCreateFontFromDC", "UPtr", DC, "UPtr*", PFONT)
      DllCall("User32.dll\ReleaseDC", "UPtr", HWND, "UPtr", DC)
      If !(This.Font := PFONT)
         Return This.SetError("Couldn't get button's font!")
      ; ----------------------------------------------------------------------------------------------------------------
      ; Get the button's rectangle
      VarSetCapacity(RECT, 16, 0)
      If !DllCall("User32.dll\GetWindowRect", "UPtr", HWND, "UPtr", &RECT)
         Return This.SetError("Couldn't get button's rectangle!")
      BtnW := NumGet(RECT,  8, "Int") - NumGet(RECT, 0, "Int")
      BtnH := NumGet(RECT, 12, "Int") - NumGet(RECT, 4, "Int")
      ; ----------------------------------------------------------------------------------------------------------------
      ; Get the button's caption
      ControlGetText, BtnCaption, , ahk_id %HWND%
      If (ErrorLevel)
         Return This.SetError("Couldn't get button's caption!")
      ; ----------------------------------------------------------------------------------------------------------------
      ; Create a GDI+ bitmap
      DllCall("Gdiplus.dll\GdipCreateBitmapFromScan0", "Int", BtnW, "Int", BtnH, "Int", 0
            , "UInt", 0x26200A, "UPtr", 0, "UPtr*", PBITMAP)
      If !(This.Bitmap := PBITMAP)
         Return This.SetError("Couldn't create the GDI+ bitmap!")
      ; Get the pointer to its graphics
      PGRAPHICS := 0
      DllCall("Gdiplus.dll\GdipGetImageGraphicsContext", "UPtr", PBITMAP, "UPtr*", PGRAPHICS)
      If !(This.Graphics := PGRAPHICS)
         Return This.SetError("Couldn't get the the GDI+ bitmap's graphics!")
      ; Quality settings
      DllCall("Gdiplus.dll\GdipSetSmoothingMode", "UPtr", PGRAPHICS, "UInt", 4)
      DllCall("Gdiplus.dll\GdipSetInterpolationMode", "UPtr", PGRAPHICS, "Int", 7)
      DllCall("Gdiplus.dll\GdipSetCompositingQuality", "UPtr", PGRAPHICS, "UInt", 4)
      DllCall("Gdiplus.dll\GdipSetRenderingOrigin", "UPtr", PGRAPHICS, "Int", 0, "Int", 0)
      DllCall("Gdiplus.dll\GdipSetPixelOffsetMode", "UPtr", PGRAPHICS, "UInt", 4)
      ; ----------------------------------------------------------------------------------------------------------------
      ; Create the bitmap(s)
      This.BitMaps := []
      For Idx, Opt In Options {
         If !IsObject(Opt)
            Continue
         BkgColor1 := BkgColor2 := TxtColor := Mode := Rounded := GuiColor := Image := ""
         ; Replace omitted options with the values of Options.1
         Loop, % This.MaxOptions {
            If (Opt[A_Index] = "")
               Opt[A_Index] := Options[1, A_Index]
         }
         ; -------------------------------------------------------------------------------------------------------------
         ; Check option values
         ; Mode
         Mode := SubStr(Opt[1], 1 ,1)
         If !InStr("0123456789", Mode)
            Return This.SetError("Invalid value for Mode in Options[" . Idx . "]!")
         ; StartColor & TargetColor
         If (Mode = 0) && This.BitmapOrIcon(Opt[2], Opt[3])
            Image := Opt[2]
         Else {
            If !This.IsInt(Opt[2]) && !This.HTML.HasKey(Opt[2])
               Return This.SetError("Invalid value for StartColor in Options[" . Idx . "]!")
            BkgColor1 := This.GetARGB(Opt[2])
            If (Opt[3] = "")
               Opt[3] := Opt[2]
            If !This.IsInt(Opt[3]) && !This.HTML.HasKey(Opt[3])
               Return This.SetError("Invalid value for TargetColor in Options[" . Idx . "]!")
            BkgColor2 := This.GetARGB(Opt[3])
         }
         ; TextColor
         If (Opt[4] = "")
            Opt[4] := This.DefTxtColor
         If !This.IsInt(Opt[4]) && !This.HTML.HasKey(Opt[4])
            Return This.SetError("Invalid value for TxtColor in Options[" . Idx . "]!")
         TxtColor := This.GetARGB(Opt[4])
         ; Rounded
         Rounded := Opt[5]
         If (Rounded = "H")
            Rounded := BtnH * 0.5
         If (Rounded = "W")
            Rounded := BtnW * 0.5
         If ((Rounded + 0) = "")
            Rounded := 0
         ; GuiColor
         If (Opt[6] = "")
            Opt[6] := This.DefGuiColor
         If !This.IsInt(Opt[6]) && !This.HTML.HasKey(Opt[6])
            Return This.SetError("Invalid value for GuiColor in Options[" . Idx . "]!")
         GuiColor := This.GetARGB(Opt[6])
         ; BorderColor
         BorderColor := ""
         If (Opt[7] <> "") {
            If !This.IsInt(Opt[7]) && !This.HTML.HasKey(Opt[7])
               Return This.SetError("Invalid value for BorderColor in Options[" . Idx . "]!")
            BorderColor := 0xFF000000 | This.GetARGB(Opt[7]) ; BorderColor must be always opaque
         }
         ; BorderWidth
         BorderWidth := Opt[8] ? Opt[8] : 1
         ; -------------------------------------------------------------------------------------------------------------
         ; Clear the background
         DllCall("Gdiplus.dll\GdipGraphicsClear", "UPtr", PGRAPHICS, "UInt", GuiColor)
         ; Create the image
         If (Image = "") { ; Create a BitMap based on the specified colors
            PathX := PathY := 0, PathW := BtnW, PathH := BtnH
            ; Create a GraphicsPath
            DllCall("Gdiplus.dll\GdipCreatePath", "UInt", 0, "UPtr*", PPATH)
            If (Rounded < 1) ; the path is a rectangular rectangle
               This.PathAddRectangle(PPATH, PathX, PathY, PathW, PathH)
            Else ; the path is a rounded rectangle
               This.PathAddRoundedRect(PPATH, PathX, PathY, PathW, PathH, Rounded)
            ; If BorderColor and BorderWidth are specified, 'draw' the border (not for Mode 7)
            If (BorderColor <> "") && (BorderWidth > 0) && (Mode <> 7) {
               ; Create a SolidBrush
               DllCall("Gdiplus.dll\GdipCreateSolidFill", "UInt", BorderColor, "UPtr*", PBRUSH)
               ; Fill the path
               DllCall("Gdiplus.dll\GdipFillPath", "UPtr", PGRAPHICS, "UPtr", PBRUSH, "UPtr", PPATH)
               ; Free the brush
               DllCall("Gdiplus.dll\GdipDeleteBrush", "UPtr", PBRUSH)
               ; Reset the path
               DllCall("Gdiplus.dll\GdipResetPath", "UPtr", PPATH)
               ; Add a new 'inner' path
               PathX := PathY := BorderWidth, PathW -= BorderWidth, PathH -= BorderWidth, Rounded -= BorderWidth
               If (Rounded < 1) ; the path is a rectangular rectangle
                  This.PathAddRectangle(PPATH, PathX, PathY, PathW - PathX, PathH - PathY)
               Else ; the path is a rounded rectangle
                  This.PathAddRoundedRect(PPATH, PathX, PathY, PathW, PathH, Rounded)
               ; If a BorderColor has been drawn, BkgColors must be opaque
               BkgColor1 := 0xFF000000 | BkgColor1
               BkgColor2 := 0xFF000000 | BkgColor2               
            }
            PathW -= PathX
            PathH -= PathY
            PBRUSH := 0
            If (Mode = 0) { ; the background is unicolored
               ; Create a SolidBrush
               DllCall("Gdiplus.dll\GdipCreateSolidFill", "UInt", BkgColor1, "UPtr*", PBRUSH)
               ; Fill the path
               DllCall("Gdiplus.dll\GdipFillPath", "UPtr", PGRAPHICS, "UPtr", PBRUSH, "UPtr", PPATH)
            }
            Else If (Mode = 1) || (Mode = 2) { ; the background is bicolored
               ; Create a LineGradientBrush
               This.SetRectF(RECTF, PathX, PathY, PathW, PathH)
               DllCall("Gdiplus.dll\GdipCreateLineBrushFromRect", "UPtr", &RECTF
                     , "UInt", BkgColor1, "UInt", BkgColor2, "Int", Mode & 1, "Int", 3, "UPtr*", PBRUSH)
               DllCall("Gdiplus.dll\GdipSetLineGammaCorrection", "UPtr", PBRUSH, "Int", 1)
               ; Set up colors and positions
               This.SetRect(COLORS, BkgColor1, BkgColor1, BkgColor2, BkgColor2) ; sorry for function misuse
               This.SetRectF(POSITIONS, 0, 0.5, 0.5, 1) ; sorry for function misuse
               DllCall("Gdiplus.dll\GdipSetLinePresetBlend", "UPtr", PBRUSH
                     , "UPtr", &COLORS, "UPtr", &POSITIONS, "Int", 4)
               ; Fill the path
               DllCall("Gdiplus.dll\GdipFillPath", "UPtr", PGRAPHICS, "UPtr", PBRUSH, "UPtr", PPATH)
            }
            Else If (Mode >= 3) && (Mode <= 6) { ; the background is a gradient
               ; Determine the brush's width/height
               W := Mode = 6 ? PathW / 2 : PathW  ; horizontal
               H := Mode = 5 ? PathH / 2 : PathH  ; vertical
               ; Create a LineGradientBrush
               This.SetRectF(RECTF, PathX, PathY, W, H)
               DllCall("Gdiplus.dll\GdipCreateLineBrushFromRect", "UPtr", &RECTF
                     , "UInt", BkgColor1, "UInt", BkgColor2, "Int", Mode & 1, "Int", 3, "UPtr*", PBRUSH)
               DllCall("Gdiplus.dll\GdipSetLineGammaCorrection", "UPtr", PBRUSH, "Int", 1)
               ; Fill the path
               DllCall("Gdiplus.dll\GdipFillPath", "UPtr", PGRAPHICS, "UPtr", PBRUSH, "UPtr", PPATH)
            }
            Else { ; raised mode
               DllCall("Gdiplus.dll\GdipCreatePathGradientFromPath", "UPtr", PPATH, "UPtr*", PBRUSH)
               ; Set Gamma Correction
               DllCall("Gdiplus.dll\GdipSetPathGradientGammaCorrection", "UPtr", PBRUSH, "UInt", 1)
               ; Set surround and center colors
               VarSetCapacity(ColorArray, 4, 0)
               NumPut(BkgColor1, ColorArray, 0, "UInt")
               DllCall("Gdiplus.dll\GdipSetPathGradientSurroundColorsWithCount", "UPtr", PBRUSH, "UPtr", &ColorArray
                   , "IntP", 1)
               DllCall("Gdiplus.dll\GdipSetPathGradientCenterColor", "UPtr", PBRUSH, "UInt", BkgColor2)
               ; Set the FocusScales
               FS := (BtnH < BtnW ? BtnH : BtnW) / 3
               XScale := (BtnW - FS) / BtnW
               YScale := (BtnH - FS) / BtnH
               DllCall("Gdiplus.dll\GdipSetPathGradientFocusScales", "UPtr", PBRUSH, "Float", XScale, "Float", YScale)
               ; Fill the path
               DllCall("Gdiplus.dll\GdipFillPath", "UPtr", PGRAPHICS, "UPtr", PBRUSH, "UPtr", PPATH)
            }
            ; Free resources
            DllCall("Gdiplus.dll\GdipDeleteBrush", "UPtr", PBRUSH)
            DllCall("Gdiplus.dll\GdipDeletePath", "UPtr", PPATH)
         } Else { ; Create a bitmap from HBITMAP or file
            If This.IsInt(Image)
               If (Opt[3] = "HICON")
                  DllCall("Gdiplus.dll\GdipCreateBitmapFromHICON", "UPtr", Image, "UPtr*", PBM)
               Else
                  DllCall("Gdiplus.dll\GdipCreateBitmapFromHBITMAP", "UPtr", Image, "UPtr", 0, "UPtr*", PBM)
            Else
               DllCall("Gdiplus.dll\GdipCreateBitmapFromFile", "WStr", Image, "UPtr*", PBM)
            ; Draw the bitmap
            DllCall("Gdiplus.dll\GdipDrawImageRectI", "UPtr", PGRAPHICS, "UPtr", PBM, "Int", 0, "Int", 0
                  , "Int", BtnW, "Int", BtnH)
            ; Free the bitmap
            DllCall("Gdiplus.dll\GdipDisposeImage", "UPtr", PBM)
         }
         ; -------------------------------------------------------------------------------------------------------------
         ; Draw the caption
         If (BtnCaption <> "") {
            ; Create a StringFormat object
            DllCall("Gdiplus.dll\GdipStringFormatGetGenericTypographic", "UPtr*", HFORMAT)
            ; Text color
            DllCall("Gdiplus.dll\GdipCreateSolidFill", "UInt", TxtColor, "UPtr*", 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", "UPtr", HFORMAT, "Int", HALIGN)
            ; Vertical alignment
            VALIGN := (BtnStyle & BS_VCENTER) = BS_TOP ? 0
                    : (BtnStyle & BS_VCENTER) = BS_BOTTOM ? 2
                    : 1
            DllCall("Gdiplus.dll\GdipSetStringFormatLineAlign", "UPtr", HFORMAT, "Int", VALIGN)
            DllCall("gdiplus\GdipSetStringFormatHotkeyPrefix", "UPtr", HFORMAT, "uint", 1)
             ; Set render quality to system default
            DllCall("Gdiplus.dll\GdipSetTextRenderingHint", "UPtr", PGRAPHICS, "Int", 0)
            ; Set the text's rectangle
            VarSetCapacity(RECT, 16, 0)
            NumPut(BtnW, RECT,  8, "Float")
            NumPut(BtnH, RECT, 12, "Float")
            ; Draw the text
            DllCall("Gdiplus.dll\GdipDrawString", "UPtr", PGRAPHICS, "WStr", BtnCaption, "Int", -1
                  , "UPtr", PFONT, "UPtr", &RECT, "UPtr", HFORMAT, "UPtr", PBRUSH)
         }
         ; -------------------------------------------------------------------------------------------------------------
         ; Create a HBITMAP handle from the bitmap and add it to the array
         DllCall("Gdiplus.dll\GdipCreateHBITMAPFromBitmap", "UPtr", PBITMAP, "UPtr*", HBITMAP, "UInt", 0X00FFFFFF)
         This.BitMaps[Idx] := HBITMAP
         ; Free resources
         DllCall("Gdiplus.dll\GdipDeleteBrush", "UPtr", PBRUSH)
         DllCall("Gdiplus.dll\GdipDeleteStringFormat", "UPtr", HFORMAT)
      }
      ; Now free remaining the GDI+ objects
      DllCall("Gdiplus.dll\GdipDisposeImage", "UPtr", PBITMAP)
      DllCall("Gdiplus.dll\GdipDeleteGraphics", "UPtr", PGRAPHICS)
      DllCall("Gdiplus.dll\GdipDeleteFont", "UPtr", PFONT)
      This.Delete("Bitmap")
      This.Delete("Graphics")
      This.Delete("Font")
      ; ----------------------------------------------------------------------------------------------------------------
      ; Create the ImageList
      HIL := DllCall("Comctl32.dll\ImageList_Create"
                   , "UInt", BtnW, "UInt", BtnH, "UInt", ILC_COLOR32, "Int", 6, "Int", 0, "Ptr")
      Loop, % (This.BitMaps.MaxIndex() > 1 ? 6 : 1) {
         HBITMAP := This.BitMaps.HasKey(A_Index) ? This.BitMaps[A_Index] : This.BitMaps.1
         DllCall("Comctl32.dll\ImageList_Add", "UPtr", HIL, "UPtr", HBITMAP, "UPtr", 0)
      }
      ; Create a BUTTON_IMAGELIST structure
      VarSetCapacity(BIL, 20 + A_PtrSize, 0)
      ; Get the currently assigned image list
      DllCall("User32.dll\SendMessage", "UPtr", HWND, "UInt", BCM_GETIMAGELIST, "UPtr", 0, "UPtr", &BIL)
      IL := NumGet(BIL, "UPtr")
      ; Create a new BUTTON_IMAGELIST structure
      VarSetCapacity(BIL, 20 + A_PtrSize, 0)
      NumPut(HIL, BIL, 0, "UPtr")
      NumPut(BUTTON_IMAGELIST_ALIGN_CENTER, BIL, A_PtrSize + 16, "UInt")
      Control, Style, +%BS_BITMAP%, , ahk_id %HWND%
      ; Remove the currently assigned image list, if any
      If (IL)
         IL_Destroy(IL)
      ; Assign the ImageList to the button
      DllCall("User32.dll\SendMessage", "UPtr", HWND, "UInt", BCM_SETIMAGELIST, "UPtr", 0, "UPtr", 0)
      DllCall("User32.dll\SendMessage", "UPtr", HWND, "UInt", BCM_SETIMAGELIST, "UPtr", 0, "UPtr", &BIL)
      ; Free the bitmaps
      This.FreeBitmaps()
      ; ----------------------------------------------------------------------------------------------------------------
      ; All done successfully
      Return True
   }
   ; ===================================================================================================================
   ; Set the default GUI color
   SetGuiColor(GuiColor) {
      ; GuiColor     -  RGB integer value (0xRRGGBB) or HTML color name ("Red").
      If !(GuiColor + 0) && !This.HTML.HasKey(GuiColor)
         Return False
      This.DefGuiColor := (This.HTML.HasKey(GuiColor) ? This.HTML[GuiColor] : GuiColor) & 0xFFFFFF
      Return True
   }
   ; ===================================================================================================================
   ; Set the default text color
   SetTxtColor(TxtColor) {
      ; TxtColor     -  RGB integer value (0xRRGGBB) or HTML color name ("Red").
      If !(TxtColor + 0) && !This.HTML.HasKey(TxtColor)
         Return False
      This.DefTxtColor := (This.HTML.HasKey(TxtColor) ? This.HTML[TxtColor] : TxtColor) & 0xFFFFFF
      Return True
   }
}


v1.6.00.00/2023-01-31/marius-sucan
It now allows to use & to underline the accelerator key for the button, and they are no longer broken, they work.
The border option works with mode 0 also. (it was workin, i was dumb)

Updated to reflect the discussion below.

Best regards, Marius.
Last edited by robodesign on 02 Feb 2023, 11:14, edited 1 time in total.
-------------------------
KeyPress OSD v4: GitHub or forum. (presentation video)
Quick Picto Viewer: GitHub or forum.
AHK GDI+ expanded / compilation library (on GitHub)
My home page.

just me
Posts: 9453
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: [Class] ImageButton - 1.5.00.00 - 20201230

Post by just me » 02 Feb 2023, 10:12

Moin @robodesign,

why did you change this:

Code: Select all

            If (Mode = 0) { ; the background is unicolored
               ; Create a SolidBrush
               DllCall("Gdiplus.dll\GdipCreateSolidFill", "UInt", BkgColor1, "UPtr*", PBRUSH)
               ; Fill the path
               DllCall("Gdiplus.dll\GdipFillPath", "UPtr", PGRAPHICS, "UPtr", PBRUSH, "UPtr", PPATH)
               If (BorderColor!="" && BorderWidth>0) {
                  rrrr := DllCall("gdiplus\GdipCreatePen1", "UInt", BorderColor, "float", BorderWidth, "int", 2, "UPtr*", pPen)
                  If !rrrr
                  {
                     DllCall("gdiplus\GdipDrawRectangle", "UPtr", PGRAPHICS, "UPtr", pPen, "float", 0, "float", 0, "float", BtnW, "float", BtnH)
                     DllCall("gdiplus\GdipDeletePen", "UPtr", pPen)
                  }
               }
            }
The 'border' has already been drawn at this stage.
7 BorderColor optional, ignored for modes 0 (bitmap) and 7, color of the border:
8 BorderWidth optional, ignored for modes 0 (bitmap) and 7, width of the border in pixels:

robodesign wrote: It now allows to use & to underline the accelerator key for the button, and they are no longer broken, they work.
They weren't broken, they could not work because the original caption was removed from the buttons to support Win XP and previous versions. It's a well known issue. ;)

robodesign
Posts: 934
Joined: 30 Sep 2017, 03:59
Location: Romania
Contact:

Re: [Class] ImageButton - 1.5.00.00 - 20201230

Post by robodesign » 02 Feb 2023, 11:10

just me wrote:
02 Feb 2023, 10:12
Moin @robodesign,

why did you change this:

Code: Select all

            If (Mode = 0) { ; the background is unicolored
               ; Create a SolidBrush
               DllCall("Gdiplus.dll\GdipCreateSolidFill", "UInt", BkgColor1, "UPtr*", PBRUSH)
               ; Fill the path
               DllCall("Gdiplus.dll\GdipFillPath", "UPtr", PGRAPHICS, "UPtr", PBRUSH, "UPtr", PPATH)
               If (BorderColor!="" && BorderWidth>0) {
                  rrrr := DllCall("gdiplus\GdipCreatePen1", "UInt", BorderColor, "float", BorderWidth, "int", 2, "UPtr*", pPen)
                  If !rrrr
                  {
                     DllCall("gdiplus\GdipDrawRectangle", "UPtr", PGRAPHICS, "UPtr", pPen, "float", 0, "float", 0, "float", BtnW, "float", BtnH)
                     DllCall("gdiplus\GdipDeletePen", "UPtr", pPen)
                  }
               }
            }
The 'border' has already been drawn at this stage.
7 BorderColor optional, ignored for modes 0 (bitmap) and 7, color of the border:
8 BorderWidth optional, ignored for modes 0 (bitmap) and 7, width of the border in pixels:

robodesign wrote: It now allows to use & to underline the accelerator key for the button, and they are no longer broken, they work.
They weren't broken, they could not work because the original caption was removed from the buttons to support Win XP and previous versions. It's a well known issue. ;)
Hey, @just me . Yes, my bad, I misread that section. I apologies. Thank you .

Regarding WinXP, I think it is better to keep the label.

I will update the initial post.

Best regards, Marius.
-------------------------
KeyPress OSD v4: GitHub or forum. (presentation video)
Quick Picto Viewer: GitHub or forum.
AHK GDI+ expanded / compilation library (on GitHub)
My home page.

dbgba
Posts: 20
Joined: 02 Apr 2021, 22:11

Re: [Class] ImageButton - 1.5.00.00 - 20201230

Post by dbgba » 05 Aug 2023, 04:39

Thanks to @just me and @tmplinshi
I've added Base64 support and batch replace function on your base to make ImageButton more convenient to use in Gui.
Any modifications or corrections are welcome!

20230805174656.gif
20230805174656.gif (40.76 KiB) Viewed 853 times

Demo.ahk

Code: Select all

#Include <Class_ImageButton>

Gui, Color, White

Gui Add, Text, Section x20 y10, Checkbox style demo

Gui Add, Checkbox, xs+10 yp+20, Test1
Gui Add, Checkbox, Section xs+10 y+8 Checked, Test2

Gui Add, Text, Section xs-10 yp+26, Click to button toggle styles
Gui Add, Button, xs+10 yp+18 w110 h50 hwndHBT1 Left gIBStyleFunc, IB Styles
Button_style := [ { 1:0, 2:0x80F4F4F4, 5:3, 6:0xFFFFFFFF, 7:0xBCC4D0, 8:1, icon:{HICON:LoadPicture("Shell32", "Icon166", _ )} }  ; normal
             , { 1:0, 2:0x80BEE7FD, 5:3, 6:0xFFFFFFFF, 7:0xBCC4D0, 8:1, icon:{HICON:LoadPicture("Shell32", "Icon3", _ )} }  ; hover
             , { 1:0, 2:0x80FBFBFB, 5:3, 6:0xFFFFFFFF, 7:0xBCC4D0, 8:1, icon:{HICON:LoadPicture("Shell32", "Icon3", _ )} } ]  ; pressed
; , { 1:0, 2:0x80FBFBFB, 5:3, 6:0xFFFFFFFF, 7:0xBCC4D0, 8:1, icon:{file:"Resources\save.png"} }
ImageButton.Create(HBT1, Button_style*)  ; ImageButton custom style


Gui Add, Text, xs yp+60, Radio style demo

Gui Add, Radio, xs+10 yp+20 Checked, Test3
Gui Add, Radio, xs+10 y+8, Test4

Gui Add, Text, xs yp+28, Other Control demo
Gui Add, Edit, xs+14 y+8 w42 r1 Limit3 Number, edit
Gui Add, UpDown, , 30

Gui Font, s12 W560, Microsoft YaHei UI
Gui Add, Checkbox, xs yp+40 Checked, Mouse Button Tips

Gui Add, Button, Section yp+28, Test5
IBStyle()  ; To replace the style of a single control, just call IBStyle() after the control.
Gui Add, Button, ys, Test6

; IBStyle(0)  ; You can batch replace controls before Gui, Show.

Gui, Show,, Image Buttons
Return


IBStyleFunc:
    IBStyle(0)  ; When the parameter is 0, batch replace the control
Return


IBStyle(Extremity:=1, ControlMove:=1, GuiHwnd:="", bgColor:="") {
   Static init
   if !init
      ImageButton.DisableFadeEffect(), init := 1

   DetectHiddenWindows % ("On", DHW:=A_DetectHiddenWindows)
   if !GuiHwnd
      WinGet, GuiHwnd, IDLast, % "ahk_class AutoHotkeyGUI ahk_pid " DllCall("GetCurrentProcessId")
   WinGet, GuiControlList, ControlList, ahk_id %GuiHwnd%  ; Iterate over control class names
   GuiControlList := StrSplit(GuiControlList, "`n")
   WinGet, GuiControlListHwnd, ControlListHwnd, ahk_id %GuiHwnd%  ; Iterate over the control Hwnd
   GuiControlListHwnd := StrSplit(GuiControlListHwnd, "`n")

   if (bgColor="") {
      hdc := DllCall("GetDC", "Ptr", GuiHwnd)
      bgPC := DllCall("GetPixel", "Ptr", hdc, "int", 1, "int", 1)
      DllCall("ReleaseDC", "Ptr", GuiHwnd, "Ptr", hdc)
      bgColor := Format("0x{:X}", ((bgPC&0xFF)<<16)|(bgPC&0xFF00)|((bgPC&0xFF0000)>>16))
      ImageButton.SetGuiColor(bgColor)  ; Setting the background color of a control
   } else
      ImageButton.SetGuiColor(bgColor)

   Loop % GuiControlList.Length() {
      if ( A_Index = (Extremity ? GuiControlList.Length() : A_Index) )
         if InStr(GuiControlList[A_Index], "Button") {
            ControlGet, ControlStyle, Style, , % GuiControlList[A_Index], ahk_id %GuiHwnd%  ; Control Style
            ; MsgBox % ControlStyle "`n" GuiControlList[A_Index] "`n" SubStr(ControlStyle, -0)
            if (SubStr(ControlStyle, -0)=0) and (SubStr(ControlStyle, -1, 1)!=8) {  ; 0=Button,  8=Style replaced
               IBBtnStyles := [ [0, 0x80F4F4F4, , , 3, 0xFFFFFFFF, 0x80A7A7A7, 1]  ; normal
                           , [0, 0x80BEE7FD, , , 3, 0xFFFFFFFF, 0x80A7A7A7, 1]  ; hover
                           , [0, 0x80FBFBFB, , , 3, 0xFFFFFFFF, 0x80A7A7A7, 1]  ; pressed
                           , [0, 0x80F0F0F0, , , 3, 0xFFFFFFFF, 0x80A7A7A7, 1] ]  ; disabled
               ImageButton.Create(GuiControlListHwnd[A_Index], IBBtnStyles*)
            } else if (SubStr(ControlStyle, -0)=3) and !(SubStr(ControlStyle, -3, 1)&1) {  ; 3=CheckBox,  even number=Unreplaced style
               GuiControl, +Left, % GuiControlListHwnd[A_Index]
               GuiControlGet, _, Pos, % GuiControlListHwnd[A_Index]
               GuiControl, Move, % GuiControlListHwnd[A_Index], % (ControlMove=1 ? "x" _X-10 " y" _Y-6 : "") " w" _W+12 " h" (_H<=22 ? 22 : _H)
               IBcbStyles := [ { icon:{ Base64:"iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOBAMAAADtZjDiAAAAElBMVEXw8fLFx8uxs7f19fb////T1NebmvpZAAAAAHRSTlM2uXDMAAAAIElEQVR42mNgVAIBAQZhFxAwZFAB005UoyHmmjJA7QEAx24V7xnl4mYAAAAASUVORK5CYII="} }  ; cb-leave
                        , { icon:{ Base64:"iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOAgMAAABiJsVCAAAADFBMVEX///8Ac/+hy/8agf/EzqNfAAAAAHRSTlM2uXDMAAAAHUlEQVR42mPYGhr6gOEBA8MGBgcGBgHSCLA2kAEAey4Kv6KPt+gAAAAASUVORK5CYII="} }  ; cb-hover
                        , { icon:{ Base64:"iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOBAMAAADtZjDiAAAAJ1BMVEUBc/8Gdv/5/P+t0f8fg/+Zxv8agf+NwP9EmP9ur//K4/8xjf/i8P/oPvn3AAAAAHRSTlM2uXDMAAAAOklEQVR42mMwYQCBZIYEMM3CgA0wQhQxCGsAia0CjEETgXSTIas6SJBDqygALCujDlU+AVkvzFyoPQBjFwa2+jygRAAAAABJRU5ErkJggg=="} } ]  ; cb-checked
               ImageButton.Create(GuiControlListHwnd[A_Index], IBcbStyles*)
            } else if (SubStr(ControlStyle, -0)=9) and !(SubStr(ControlStyle, -3, 1)&1) {  ; 9=Radio,  even number=Unreplaced style
               GuiControl, +Left, % GuiControlListHwnd[A_Index]
               GuiControlGet, _, Pos, % GuiControlListHwnd[A_Index]
               GuiControl, Move, % GuiControlListHwnd[A_Index], % (ControlMove=1 ? "x" _X-10 " y" _Y-6 : "") " w" _W+12 " h" (_H<=22 ? 22 : _H)
               IBRadioStyles := [ { icon:{ Base64:"iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOBAMAAADtZjDiAAAAGFBMVEUAAAD////P0dX29/fi4uLNzc3t7u/7+/s5YSwrAAAAAXRSTlMAQObYZgAAAEVJREFUeNpjYGB3VQopYGBgSHIWNFFjYGALFhQUNE1gKDIE0sLqDC6CIODCEAymTRkUwbQQnIaJw9TB9IHNMUqAmwu1BwDweA1oBqqPSQAAAABJRU5ErkJggg=="} }  ; radio-leave
                        , { icon:{ Base64:"iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOBAMAAADtZjDiAAAAIVBMVEUAAAD///8Id/+21/+Auv/x9/8ui/9Jmv/g7v/Z6v+92/8+MrWnAAAAAXRSTlMAQObYZgAAAEdJREFUeNpjYOBwU0ppYGBgMKoKNVdmYGDWFBQUnGTA0DQRSEtqMLgLgkAJQxaYNmNQBdNBcDoZKg5TB9MHM4fBqBhsLtQeAI+FEEPqNBPaAAAAAElFTkSuQmCC"} }  ; radio-hover
                        , { icon:{ Base64:"iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOBAMAAADtZjDiAAAAMFBMVEUAAAD///8Bc/+11f8Gdf8LeP9Jmv/W6P+jy/8khv9+uP/j7/8vjP/1+f/w9v82kP+DkUdiAAAAAXRSTlMAQObYZgAAAFFJREFUeNpjYOBeE3pqAwMDg0nyXTNnBgbmcEFBwVIDhi2FEjMbxb0Zlgl+UtIXzGI4LKGkpNRow+ArCaQnPoXTMHGYOpg+mDlAc9+BzIXaAwCXvh44eE6aVgAAAABJRU5ErkJggg=="} } ]  ; radio-checked
               ImageButton.Create(GuiControlListHwnd[A_Index], IBRadioStyles*)
            }
         }
   }
   DetectHiddenWindows %DHW%
}

/*
Gui Add, Slider, w1 h1  ; Control=msctls_trackbar321
WM_CTLCOLORBTN(wParam, lParam) {
	Static init:=OnMessage(0x135, "WM_CTLCOLORBTN")
	if GetKeyState("LButton") {
		MouseGetPos, , , ImageButtonGuiHwnd, Control
		_:=Func(A_ThisFunc).Bind(ImageButtonGuiHwnd, Control)
		SetTimer %_%, -150
	} else if InStr(lParam, "Button") {
		ControlClick, Button1, ahk_id %wParam%
		; SendMessage, 0x8, 0, 0, %lParam%, ahk_id %wParam%
	}
	; Tooltip % wParam ", " lParam
}
*/

GuiClose:
GuiEscape:
ExitApp

Class_ImageButton.ahk

Code: Select all

; Modified from: https://github.com/AHK-just-me/Class_ImageButton
; Modified from: https://github.com/tmplinshi/Class_ImageButton
; =============================================================
; Namespace:         ImageButton
; Function:          Create images and assign them to pushbuttons.
; Tested with:       AHK 1.1.33.02 (A32/U32/U64)
; Tested on:         Win 10 (x64)
; Change history:             /2023-08-05/dbgba - added Icon.Base64, Synchronization of 1.5 parts
;                              /2017-02-05/tmplinshi - added DisableFadeEffect(). Thanks to Klark92.
;                             /2017-01-21/tmplinshi - added support for icon and checkbox/radio buttons
;                    1.4.00.00/2014-06-07/just me - fixed bug for button caption = "0", "000", etc.
;                    1.3.00.00/2014-02-28/just me - added support for ARGB colors
;                    1.2.00.00/2014-02-23/just me - added borders
;                    1.1.00.00/2013-12-26/just me - added rounded and bicolored buttons       
;                    1.0.00.00/2013-12-21/just me - initial release
; How to use:
;     1. Create a push button (e.g. "Gui, Add, Button, vMyButton hwndHwndButton, Caption") using the 'Hwnd' option
;        to get its HWND.
;     2. Call ImageButton.Create() passing two parameters:
;        HWND        -  Button's HWND.
;        Options*    -  variadic array containing up to 6 option arrays (see below).
;        ---------------------------------------------------------------------------------------------------------------
;        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):
;           PBS_NORMAL    = 1
;	         PBS_HOT       = 2
;	         PBS_PRESSED   = 3
;	         PBS_DISABLED  = 4
;	         PBS_DEFAULTED = 5
;	         PBS_STYLUSHOT = 6 <- used only on tablet computers (that's false for Windows Vista and 7, see below)
;        If you don't want the button to be 'animated' on themed GUIs, just pass one option object with index 1.
;        On Windows Vista and 7 themed bottons are 'animated' using the images of states 5 and 6 after clicked.
;        ---------------------------------------------------------------------------------------------------------------
;        Each option array may contain the following values:
;           Index Value
;           1     Mode        mandatory:
;                             0  -  unicolored or bitmap
;                             1  -  vertical bicolored
;                             2  -  horizontal bicolored
;                             3  -  vertical gradient
;                             4  -  horizontal gradient
;                             5  -  vertical gradient using StartColor at both borders and TargetColor at the center
;                             6  -  horizontal gradient using StartColor at both borders and TargetColor at the center
;                             7  -  'raised' style
;           2     StartColor  mandatory for Option[1], higher indices will inherit the value of Option[1], if omitted:
;                             -  ARGB integer value (0xAARRGGBB) or HTML color name ("Red").
;                             -  Path of an image file or HBITMAP handle for mode 0.
;           3     TargetColor mandatory for Option[1] if Mode > 0, ignored if Mode = 0. Higher indcices will inherit
;                             the color of Option[1], if omitted:
;                             -  ARGB integer value (0xAARRGGBB) or HTML color name ("Red").
;                             -  String "HICON" if StartColor contains a HICON handle.
;           4     TextColor   optional, if omitted, the default text color will be used for Option[1], higher indices 
;                             will inherit the color of Option[1]:
;                             -  ARGB integer value (0xAARRGGBB) or HTML color name ("Red").
;                                Default: 0xFF000000 (black)
;           5     Rounded     optional:
;                             -  Radius of the rounded corners in pixel; the letters 'H' and 'W' may be specified
;                                also to use the half of the button's height or width respectively.
;                                Default: 0 - not rounded
;           6     GuiColor    optional, needed for rounded buttons if you've changed the GUI background color:
;                             -  RGB integer value (0xRRGGBB) or HTML color name ("Red").
;                                Default: AHK default GUI background color
;           7     BorderColor optional, ignored for modes 0 (bitmap) and 7, color of the border:
;                             -  RGB integer value (0xRRGGBB) or HTML color name ("Red").
;           8     BorderWidth optional, ignored for modes 0 (bitmap) and 7, width of the border in pixels:
;                             -  Default: 1
;        ---------------------------------------------------------------------------------------------------------------
;        If the the button has a caption it will be drawn above the bitmap.
; 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
; =============================================================
; 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.
; =============================================================
; CLASS ImageButton()
; =============================================================
Class ImageButton {
   ; =============================================================
   ; PUBLIC PROPERTIES
   ; =============================================================
   Static DefGuiColor  := ""        ; default GUI color                             (read/write)
   Static DefTxtColor := "Black"    ; default caption color                         (read/write)
   Static LastError := ""           ; will contain the last error message, if any   (readonly)
   ; =============================================================
   ; PRIVATE PROPERTIES
   ; =============================================================
   Static BitMaps := []
   Static GDIPDll := 0
   Static GDIPToken := 0
   Static MaxOptions := 8
   ; HTML colors
   Static HTML := {BLACK: 0x000000, GRAY: 0x808080, SILVER: 0xC0C0C0, WHITE: 0xFFFFFF, MAROON: 0x800000
                 , PURPLE: 0x800080, FUCHSIA: 0xFF00FF, RED: 0xFF0000, GREEN: 0x008000, OLIVE: 0x808000
                 , YELLOW: 0xFFFF00, LIME: 0x00FF00, NAVY: 0x000080, TEAL: 0x008080, AQUA: 0x00FFFF, BLUE: 0x0000FF}
   ; Initialize
   Static ClassInit := ImageButton.InitClass()
   ; =============================================================
   ; PRIVATE METHODS
   ; =============================================================
   __New(P*) {
      Return False
   }
   ; =============================================================
   InitClass() {
      ; ----------------------------------------------------------------------------------------------------------------
      ; Get AHK's default GUI background color
      GuiColor := DllCall("User32.dll\GetSysColor", "Int", 15, "UInt") ; COLOR_3DFACE is used by AHK as default
      , This.DefGuiColor := ((GuiColor >> 16) & 0xFF) | (GuiColor & 0x00FF00) | ((GuiColor & 0xFF) << 16)
      Return True
   }
   ; =============================================================
   GdiplusStartup() {
      This.GDIPDll := This.GDIPToken := 0
      If (This.GDIPDll := DllCall("Kernel32.dll\LoadLibrary", "Str", "Gdiplus.dll", "Ptr")) {
         VarSetCapacity(SI, 24, 0)
         , Numput(1, SI, 0, "Int")
         If !DllCall("Gdiplus.dll\GdiplusStartup", "PtrP", GDIPToken, "Ptr", &SI, "Ptr", 0)
            This.GDIPToken := GDIPToken
         Else
            This.GdiplusShutdown()
      }
      Return This.GDIPToken
   }
   ; =============================================================
   GdiplusShutdown() {
      If This.GDIPToken
         DllCall("Gdiplus.dll\GdiplusShutdown", "Ptr", This.GDIPToken)
      If This.GDIPDll
         DllCall("Kernel32.dll\FreeLibrary", "Ptr", This.GDIPDll)
      This.GDIPDll := This.GDIPToken := 0
   }
   ; =============================================================
   FreeBitmaps() {
      For I, HBITMAP In This.BitMaps
         DllCall("Gdi32.dll\DeleteObject", "Ptr", HBITMAP)
      This.BitMaps := []
   }
   ; =============================================================
   GetARGB(RGB) {
      ARGB := This.HTML.HasKey(RGB) ? This.HTML[RGB] : RGB
      Return (ARGB & 0xFF000000) = 0 ? 0xFF000000 | ARGB : ARGB
   }
   ; =============================================================
   PathAddRectangle(Path, X, Y, W, H) {
      Return DllCall("Gdiplus.dll\GdipAddPathRectangle", "Ptr", Path, "Float", X, "Float", Y, "Float", W, "Float", H)
   }
   ; =============================================================
   PathAddRoundedRect(Path, X1, Y1, X2, Y2, R) {
      D := (R * 2), X2 -= D, Y2 -= D
      , DllCall("Gdiplus.dll\GdipAddPathArc", "Ptr", Path, "Float", X1, "Float", Y1, "Float", D, "Float", D, "Float", 180, "Float", 90)
      , DllCall("Gdiplus.dll\GdipAddPathArc", "Ptr", Path, "Float", X2, "Float", Y1, "Float", D, "Float", D, "Float", 270, "Float", 90)
      , DllCall("Gdiplus.dll\GdipAddPathArc", "Ptr", Path, "Float", X2, "Float", Y2, "Float", D, "Float", D, "Float", 0, "Float", 90)
      , DllCall("Gdiplus.dll\GdipAddPathArc", "Ptr", Path, "Float", X1, "Float", Y2, "Float", D, "Float", D, "Float", 90, "Float", 90)
      Return DllCall("Gdiplus.dll\GdipClosePathFigure", "Ptr", Path)
   }
   ; =============================================================
   SetRect(ByRef Rect, X1, Y1, X2, Y2) {
      VarSetCapacity(Rect, 16, 0)
      , NumPut(X1, Rect, 0, "Int"), NumPut(Y1, Rect, 4, "Int")
      , NumPut(X2, Rect, 8, "Int"), NumPut(Y2, Rect, 12, "Int")
      Return True
   }
   ; =============================================================
   SetRectF(ByRef Rect, X, Y, W, H) {
      VarSetCapacity(Rect, 16, 0)
      , NumPut(X, Rect, 0, "Float"), NumPut(Y, Rect, 4, "Float")
      , NumPut(W, Rect, 8, "Float"), NumPut(H, Rect, 12, "Float")
      Return True
   }
   ; =============================================================
   SetError(Msg) {
      This.FreeBitmaps()
      , This.GdiplusShutdown()
      , This.LastError := Msg
      Return False
   }
   ; =============================================================
   ; PUBLIC METHODS
   ; =============================================================
   Create(HWND, Options*) {
      ; Windows constants
      Static BCM_GETIMAGELIST := 0x1603, BCM_SETIMAGELIST := 0x1602
           , BS_CHECKBOX := 0x02, BS_RADIOBUTTON := 0x04, BS_GROUPBOX := 0x07, BS_AUTORADIOBUTTON := 0x09
           , BS_LEFT := 0x0100, BS_RIGHT := 0x0200, BS_CENTER := 0x0300, BS_TOP := 0x0400, BS_BOTTOM := 0x0800
           , BS_VCENTER := 0x0C00, BS_BITMAP := 0x0080
           , BUTTON_IMAGELIST_ALIGN_LEFT := 0, BUTTON_IMAGELIST_ALIGN_RIGHT := 1, BUTTON_IMAGELIST_ALIGN_CENTER := 4
           , ILC_COLOR32 := 0x20
           , OBJ_BITMAP := 7
           , RCBUTTONS := BS_CHECKBOX | BS_RADIOBUTTON | BS_AUTORADIOBUTTON
           , SA_LEFT := 0x00, SA_CENTER := 0x01, SA_RIGHT := 0x02
           , WM_GETFONT := 0x31
      ; ----------------------------------------------------------------------------------------------------------------
      This.LastError := ""
      , HBITMAP := HFORMAT := PBITMAP := PBRUSH := PFONT := PPATH := 0
      ; ----------------------------------------------------------------------------------------------------------------
      ; Check HWND
      If !DllCall("User32.dll\IsWindow", "Ptr", HWND)
         Return This.SetError("Invalid parameter HWND!")
      ; ----------------------------------------------------------------------------------------------------------------
      ; Check Options
      If !(IsObject(Options)) || (Options.MinIndex() <> 1) ; || (Options.MaxIndex() > This.MaxOptions)
         Return This.SetError("Invalid parameter Options!")
      ; ----------------------------------------------------------------------------------------------------------------
      ; 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)
         Return This.SetError("The control must be a pushbutton!")
      If ((BtnStyle & RCBUTTONS) > 1)
         GuiControl, +0x1000, %HWND% ; BS_PUSHLIKE = 0x1000
      ; ----------------------------------------------------------------------------------------------------------------
      ; Load GdiPlus
      If !This.GdiplusStartup()
         Return This.SetError("GDIPlus could not be started!")
      ; ----------------------------------------------------------------------------------------------------------------
      ; Get the button's font
      HFONT := DllCall("User32.dll\SendMessage", "Ptr", HWND, "UInt", WM_GETFONT, "Ptr", 0, "Ptr", 0, "Ptr")
      , DC := DllCall("User32.dll\GetDC", "Ptr", HWND, "Ptr")
      , DllCall("Gdi32.dll\SelectObject", "Ptr", DC, "Ptr", HFONT)
      , DllCall("Gdiplus.dll\GdipCreateFontFromDC", "Ptr", DC, "PtrP", PFONT)
      , DllCall("User32.dll\ReleaseDC", "Ptr", HWND, "Ptr", DC)
      If !(PFONT)
         Return This.SetError("Couldn't get button's font!")
      ; ----------------------------------------------------------------------------------------------------------------
      ; Get the button's rectangle
      VarSetCapacity(RECT, 16, 0)
      If !DllCall("User32.dll\GetWindowRect", "Ptr", HWND, "Ptr", &RECT)
         Return This.SetError("Couldn't get button's rectangle!")
      BtnW := NumGet(RECT,  8, "Int") - NumGet(RECT, 0, "Int")
      , BtnH := NumGet(RECT, 12, "Int") - NumGet(RECT, 4, "Int")
      ; ----------------------------------------------------------------------------------------------------------------
      ; Get the button's caption
      ControlGetText, BtnCaption, , ahk_id %HWND%
      If (ErrorLevel)
         Return This.SetError("Couldn't get button's caption!")
      ; ----------------------------------------------------------------------------------------------------------------
      ; Create the bitmap(s)
      This.BitMaps := []
      For Index, Option In Options {
         If !IsObject(Option)
            Continue
         BkgColor1 := BkgColor2 := TxtColor := Mode := Rounded := GuiColor := Image := ""
         ; Replace omitted options with the values of Options.1
         Loop, % This.MaxOptions
            If (Option[A_Index] = "")
               Option[A_Index] := Options.1[A_Index]

         ; -------------------------------------------------------------------------------------------------------------
         ; Check option values
         ; Mode
         Mode := SubStr(Option.1, 1 ,1)
         If !InStr("0123456789", Mode)
            Return This.SetError("Invalid value for Mode in Options[" . Index . "]!")
         ; StartColor & TargetColor
         If (Mode = 0)
         && (FileExist(Option.2) || (DllCall("Gdi32.dll\GetObjectType", "Ptr", Option.2, "UInt") = OBJ_BITMAP))
            Image := Option.2
         Else {
            If !(Option.2 + 0) && !This.HTML.HasKey(Option.2) && !Option.Icon
               Return This.SetError("Invalid value for StartColor in Options[" . Index . "]!")
            BkgColor1 := This.GetARGB(Option.2)
            If (Option.3 = "")
               Option.3 := Option.2
            If !(Option.3 + 0) && !This.HTML.HasKey(Option.3) && !Option.Icon
               Return This.SetError("Invalid value for TargetColor in Options[" . Index . "]!")
            BkgColor2 := This.GetARGB(Option.3)
         }
         ; TextColor
         If (Option.4 = "")
            Option.4 := This.DefTxtColor
         If !(Option.4 + 0) && !This.HTML.HasKey(Option.4)
            Return This.SetError("Invalid value for TxtColor in Options[" . Index . "]!")
         TxtColor := This.GetARGB(Option.4)
         ; Rounded
         Rounded := Option.5
         If (Rounded = "H")
            Rounded := BtnH * 0.5
         If (Rounded = "W")
            Rounded := BtnW * 0.5
         If !(Rounded + 0)
            Rounded := 0
         ; GuiColor
         If (Option.6 = "")
            Option.6 := This.DefGuiColor
         If !(Option.6 + 0) && !This.HTML.HasKey(Option.6)
            Return This.SetError("Invalid value for GuiColor in Options[" . Index . "]!")
         GuiColor := This.GetARGB(Option.6)
         ; BorderColor
         , BorderColor := ""
         If (Option.7 <> "") {
            If !(Option.7 + 0) && !This.HTML.HasKey(Option.7)
               Return This.SetError("Invalid value for BorderColor in Options[" . Index . "]!")
            BorderColor := 0xFF000000 | This.GetARGB(Option.7) ; BorderColor must be always opaque
         }
         ; BorderWidth
         BorderWidth := Option.8 ? Option.8 : 1
         ; -------------------------------------------------------------------------------------------------------------
         ; Create a GDI+ bitmap
         , DllCall("Gdiplus.dll\GdipCreateBitmapFromScan0", "Int", BtnW, "Int", BtnH, "Int", 0
               , "UInt", 0x26200A, "Ptr", 0, "PtrP", PBITMAP)
         ; Get the pointer to its graphics
         , DllCall("Gdiplus.dll\GdipGetImageGraphicsContext", "Ptr", PBITMAP, "PtrP", PGRAPHICS)
         ; Quality settings
         , DllCall("Gdiplus.dll\GdipSetSmoothingMode", "Ptr", PGRAPHICS, "UInt", 4)
         , DllCall("Gdiplus.dll\GdipSetInterpolationMode", "Ptr", PGRAPHICS, "Int", 7)
         , DllCall("Gdiplus.dll\GdipSetCompositingQuality", "Ptr", PGRAPHICS, "UInt", 4)
         , DllCall("Gdiplus.dll\GdipSetRenderingOrigin", "Ptr", PGRAPHICS, "Int", 0, "Int", 0)
         , DllCall("Gdiplus.dll\GdipSetPixelOffsetMode", "Ptr", PGRAPHICS, "UInt", 4)
         ; Clear the background
         , DllCall("Gdiplus.dll\GdipGraphicsClear", "Ptr", PGRAPHICS, "UInt", GuiColor)
         ; Create the image
         If (Image = "") { ; Create a BitMap based on the specified colors
            PathX := PathY := 0, PathW := BtnW, PathH := BtnH
            ; Create a GraphicsPath
            DllCall("Gdiplus.dll\GdipCreatePath", "UInt", 0, "PtrP", PPATH)
            If (Rounded < 1) ; the path is a rectangular rectangle
               This.PathAddRectangle(PPATH, PathX, PathY, PathW, PathH)
            Else ; the path is a rounded rectangle
               This.PathAddRoundedRect(PPATH, PathX, PathY, PathW, PathH, Rounded)
            ; If BorderColor and BorderWidth are specified, 'draw' the border (not for Mode 7)
            If (BorderColor <> "") && (BorderWidth > 0) && (Mode <> 7) {
               ; Create a SolidBrush
               DllCall("Gdiplus.dll\GdipCreateSolidFill", "UInt", BorderColor, "PtrP", PBRUSH)
               ; Fill the path
               , DllCall("Gdiplus.dll\GdipFillPath", "Ptr", PGRAPHICS, "Ptr", PBRUSH, "Ptr", PPATH)
               ; Free the brush
               , DllCall("Gdiplus.dll\GdipDeleteBrush", "Ptr", PBRUSH)
               ; Reset the path
               , DllCall("Gdiplus.dll\GdipResetPath", "Ptr", PPATH)
               ; Add a new 'inner' path
               PathX := PathY := BorderWidth, PathW -= BorderWidth, PathH -= BorderWidth, Rounded -= BorderWidth
               If (Rounded < 1) ; the path is a rectangular rectangle
                  This.PathAddRectangle(PPATH, PathX, PathY, PathW - PathX, PathH - PathY)
               Else ; the path is a rounded rectangle
                  This.PathAddRoundedRect(PPATH, PathX, PathY, PathW, PathH, Rounded)
               ; If a BorderColor has been drawn, BkgColors must be opaque
               BkgColor1 := 0xFF000000 | BkgColor1
               , BkgColor2 := 0xFF000000 | BkgColor2               
            }
            PathW -= PathX
            , PathH -= PathY
            , PBRUSH := 0
            If (Mode = 0) { ; the background is unicolored
               ; Create a SolidBrush
               DllCall("Gdiplus.dll\GdipCreateSolidFill", "UInt", BkgColor1, "PtrP", PBRUSH)
               ; Fill the path
               , DllCall("Gdiplus.dll\GdipFillPath", "Ptr", PGRAPHICS, "Ptr", PBRUSH, "Ptr", PPATH)
            }
            Else If (Mode = 1) || (Mode = 2) { ; the background is bicolored
               ; Create a LineGradientBrush
               This.SetRectF(RECTF, PathX, PathY, PathW, PathH)
               , DllCall("Gdiplus.dll\GdipCreateLineBrushFromRect", "Ptr", &RECTF
                     , "UInt", BkgColor1, "UInt", BkgColor2, "Int", Mode & 1, "Int", 3, "PtrP", PBRUSH)
               , DllCall("Gdiplus.dll\GdipSetLineGammaCorrection", "Ptr", PBRUSH, "Int", 1)
               ; Set up colors and positions
               , This.SetRect(COLORS, BkgColor1, BkgColor1, BkgColor2, BkgColor2) ; sorry for function misuse
               , This.SetRectF(POSITIONS, 0, 0.5, 0.5, 1) ; sorry for function misuse
               , DllCall("Gdiplus.dll\GdipSetLinePresetBlend", "Ptr", PBRUSH, "Ptr", &COLORS, "Ptr", &POSITIONS, "Int", 4)
               ; Fill the path
               , DllCall("Gdiplus.dll\GdipFillPath", "Ptr", PGRAPHICS, "Ptr", PBRUSH, "Ptr", PPATH)
            }
            Else If (Mode >= 3) && (Mode <= 6) { ; the background is a gradient
               ; Determine the brush's width/height
               W := Mode = 6 ? PathW / 2 : PathW  ; horizontal
               , H := Mode = 5 ? PathH / 2 : PathH  ; vertical
               ; Create a LineGradientBrush
               , This.SetRectF(RECTF, PathX, PathY, W, H)
               , DllCall("Gdiplus.dll\GdipCreateLineBrushFromRect", "Ptr", &RECTF
                     , "UInt", BkgColor1, "UInt", BkgColor2, "Int", Mode & 1, "Int", 3, "PtrP", PBRUSH)
               , DllCall("Gdiplus.dll\GdipSetLineGammaCorrection", "Ptr", PBRUSH, "Int", 1)
               ; Fill the path
               , DllCall("Gdiplus.dll\GdipFillPath", "Ptr", PGRAPHICS, "Ptr", PBRUSH, "Ptr", PPATH)
            }
            Else { ; raised mode
               DllCall("Gdiplus.dll\GdipCreatePathGradientFromPath", "Ptr", PPATH, "PtrP", PBRUSH)
               ; Set Gamma Correction
               , DllCall("Gdiplus.dll\GdipSetPathGradientGammaCorrection", "Ptr", PBRUSH, "UInt", 1)
               ; Set surround and center colors
               , VarSetCapacity(ColorArray, 4, 0)
               , NumPut(BkgColor1, ColorArray, 0, "UInt")
               , DllCall("Gdiplus.dll\GdipSetPathGradientSurroundColorsWithCount", "Ptr", PBRUSH, "Ptr", &ColorArray, "IntP", 1)
               , DllCall("Gdiplus.dll\GdipSetPathGradientCenterColor", "Ptr", PBRUSH, "UInt", BkgColor2)
               ; Set the FocusScales
               , FS := (BtnH < BtnW ? BtnH : BtnW) / 3
               , XScale := (BtnW - FS) / BtnW
               , YScale := (BtnH - FS) / BtnH
               , DllCall("Gdiplus.dll\GdipSetPathGradientFocusScales", "Ptr", PBRUSH, "Float", XScale, "Float", YScale)
               ; Fill the path
               , DllCall("Gdiplus.dll\GdipFillPath", "Ptr", PGRAPHICS, "Ptr", PBRUSH, "Ptr", PPATH)
            }
            ; Free resources
            DllCall("Gdiplus.dll\GdipDeleteBrush", "Ptr", PBRUSH)
            , DllCall("Gdiplus.dll\GdipDeletePath", "Ptr", PPATH)
         } Else { ; Create a bitmap from HBITMAP or file
            If (Image + 0)
               If (Option.3 = "HICON")
                  DllCall("Gdiplus.dll\GdipCreateBitmapFromHICON", "Ptr", Image, "PtrP", PBM)
               Else
                  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", BtnW, "Int", BtnH)
            ; Free the bitmap
            , DllCall("Gdiplus.dll\GdipDisposeImage", "Ptr", PBM)
         }

         if (oIcon := Option.Icon) {
            if oIcon.file
                DllCall("Gdiplus.dll\GdipCreateBitmapFromFile", "WStr", oIcon.file, "PtrP", PBM)
             else if oIcon.Base64
                Base64 := oIcon.Base64
                , VarSetCapacity(B64Len, 0)
                , DllCall("Crypt32.dll\CryptStringToBinary", "Ptr", &Base64, "UInt", StrLen(Base64), "UInt", 0x01, "Ptr", 0, "UIntP", B64Len, "Ptr", 0, "Ptr", 0)
                , VarSetCapacity(B64Dec, B64Len, 0) ; pbBinary size
                , DllCall("Crypt32.dll\CryptStringToBinary", "Ptr", &Base64, "UInt", StrLen(Base64), "UInt", 0x01, "Ptr", &B64Dec, "UIntP", B64Len, "Ptr", 0, "Ptr", 0)
                , pStream := DllCall("Shlwapi.dll\SHCreateMemStream", "Ptr", &B64Dec, "UInt", B64Len, "UPtr")
                , DllCall("Gdiplus.dll\GdipCreateBitmapFromStreamICM", "Ptr", pStream, "PtrP", PBM)
             else if oIcon.HICON
                DllCall("Gdiplus.dll\GdipCreateBitmapFromHICON", "Ptr", oIcon.HICON, "PtrP", PBM)

            If !oIcon.w
               DllCall("Gdiplus.dll\GdipGetImageWidth", "Ptr", PBM, "UInt*", __w)
               , oIcon.w := __w

            If !oIcon.h
               DllCall("Gdiplus.dll\GdipGetImageHeight", "Ptr", PBM, "UInt*", __h)
               , oIcon.h := __h

            if !oIcon.HasKey("padding")
               oIcon.padding := 8

            if !oIcon.HasKey("y")
               oIcon.y := (BtnH - oIcon.h)//2

            icon_x := oIcon.HasKey("x") ? oIcon.x : oIcon.padding

            , DllCall("Gdiplus.dll\GdipDrawImageRectI", "Ptr", PGRAPHICS, "Ptr", PBM, "Int", icon_x, "Int", oIcon.y
                  , "Int", oIcon.w, "Int", oIcon.h)
            ; Free the bitmap
            , DllCall("Gdiplus.dll\GdipDisposeImage", "Ptr", PBM)
         }

         ; -------------------------------------------------------------------------------------------------------------
         ; Draw the caption
         If (BtnCaption <> "") {
            ; Create a StringFormat object
            DllCall("Gdiplus.dll\GdipStringFormatGetGenericTypographic", "PtrP", HFORMAT)
            ; Text color
            , DllCall("Gdiplus.dll\GdipCreateSolidFill", "UInt", 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
            , VarSetCapacity(RECT, 16, 0)

            If oIcon and (!oIcon.x or (HALIGN = SA_CENTER))
                NumPut(oIcon.w + oIcon.padding*2, RECT, 0, "Float")

            NumPut(BtnW, RECT, 8, "Float")
            , NumPut(BtnH, RECT, 12, "Float")

            ; Draw the text
            DllCall("Gdiplus.dll\GdipDrawString", "Ptr", PGRAPHICS, "WStr", BtnCaption, "Int", -1
                  , "Ptr", PFONT, "Ptr", &RECT, "Ptr", HFORMAT, "Ptr", PBRUSH)
         }
         ; -------------------------------------------------------------------------------------------------------------
         ; Create a HBITMAP handle from the bitmap and add it to the array
         DllCall("Gdiplus.dll\GdipCreateHBITMAPFromBitmap", "Ptr", PBITMAP, "PtrP", HBITMAP, "UInt", 0X00FFFFFF)
         , This.BitMaps[Index] := HBITMAP
         ; 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)
         ; Add the bitmap to the array
      }
      ; Now free the font object
      DllCall("Gdiplus.dll\GdipDeleteFont", "Ptr", PFONT)
      ; ----------------------------------------------------------------------------------------------------------------
      ; Create the ImageList
      HIL := DllCall("Comctl32.dll\ImageList_Create"
                   , "UInt", BtnW, "UInt", BtnH, "UInt", ILC_COLOR32, "Int", 6, "Int", 0, "Ptr")
      Loop, % (This.BitMaps.MaxIndex() > 1 ? 6 : 1)
         HBITMAP := This.BitMaps.HasKey(A_Index) ? This.BitMaps[A_Index] : This.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
      ControlSetText, , , ahk_id %HWND%
      Control, Style, +%BS_BITMAP%, , ahk_id %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
      This.FreeBitmaps()
      ; ----------------------------------------------------------------------------------------------------------------
      ; All done successfully
      This.GdiplusShutdown()
      Return True
   }
   ; =============================================================
   ; Set the default GUI color
   SetGuiColor(GuiColor) {
      ; GuiColor     -  RGB integer value (0xRRGGBB) or HTML color name ("Red").
      If !(GuiColor + 0) && !This.HTML.HasKey(GuiColor)
         Return False
      This.DefGuiColor := (This.HTML.HasKey(GuiColor) ? This.HTML[GuiColor] : GuiColor) & 0xFFFFFF
      Return True
   }
   ; =============================================================
   ; Set the default text color
   SetTxtColor(TxtColor) {
      ; TxtColor     -  RGB integer value (0xRRGGBB) or HTML color name ("Red").
      If !(TxtColor + 0) && !This.HTML.HasKey(TxtColor)
         Return False
      This.DefTxtColor := (This.HTML.HasKey(TxtColor) ? This.HTML[TxtColor] : TxtColor) & 0xFFFFFF
      Return True
   }
   ; =============================================================
   DisableFadeEffect() {
      ; SPI_GETCLIENTAREAANIMATION = 0x1042
      DllCall("SystemParametersInfo", "UInt", 0x1042, "UInt", 0, "UInt*", isEnabled, "UInt", 0)

      if isEnabled {
         ; SPI_SETCLIENTAREAANIMATION = 0x1043
         DllCall("SystemParametersInfo", "UInt", 0x1043, "UInt", 0, "UInt", 0, "UInt", 0)
         Progress, 10:P100 Hide
         Progress, 10:Off
         DllCall("SystemParametersInfo", "UInt", 0x1043, "UInt", 0, "UInt", 1, "UInt", 0)
      }
   }
}

; https://www.autohotkey.com/boards/viewtopic.php?p=349111#p349111
; ImageButton.OptimizeEnd()
class ImageButtonOptimize {
	static _ := ImageButton.base := ImageButtonOptimize
	static __ := ImageButton.OptimizeBegin()

	OptimizeBegin() {
		this.GdiplusStartup()
		, this.ctrlDelay := A_ControlDelay
		SetControlDelay, -1
		this.__GdiplusStartup := this.GdiplusStartup
		, this.__GdiplusShutdown := this.GdiplusShutdown
		, this.GdiplusStartup := this.ReturnTrue
		, this.GdiplusShutdown := this.ReturnTrue
	}

	OptimizeEnd() {
		this.GdiplusStartup := this.__GdiplusStartup
		, this.GdiplusShutdown := this.__GdiplusShutdown
		, this.__GdiplusStartup := ""
		, this.__GdiplusShutdown := ""
		, this.GdiplusShutdown()
		SetControlDelay, % this.ctrlDelay
	}

	ReturnTrue() {
		return true
	}
}

Post Reply

Return to “Scripts and Functions (v1)”