[Class] ImageButton - 1.5.00.00 - 20201230
Re: [Class] ImageButton - 1.5.00.00 - 20201230
@jNizM, thanks for your 'Bootstrap like Buttons'. I added a link to the OP.
- oldbrother
- Posts: 275
- Joined: 23 Oct 2013, 05:08
Re: [Class] ImageButton - 1.5.00.00 - 20201230
@jNizM, Thanks! It seems not working with ver. 1.5.
Re: [Class] ImageButton - 1.5.00.00 - 20201230
Hello everyone!
I'm playing with the "just-me" libs.
First I did it for AHK v2 and I'm adding other things, for example more gradient, support gradient angle and transparency on the edges and background.
Leave a comment on what you think.
I know there must be a lot of mistakes, but you can make fun of it...
I'm playing with the "just-me" libs.
First I did it for AHK v2 and I'm adding other things, for example more gradient, support gradient angle and transparency on the edges and background.
Leave a comment on what you think.
I know there must be a lot of mistakes, but you can make fun of it...
Code: Select all
/*
Return:
Errors:
-1 : Invalid parameter "target".
-2 : Invalid parameter "properties"
-3 : GDIPlus could not be started
-4 : This button does not have the required styles
-5 : Couldn't get button's font
-6 : Couldn't get button's rectangle
-7 : Couldn't create the Gdiplus bitmap
-8 : Couldn't get the the Gdiplus bitmap's graphics
-9 : Could not get background from properties
-10: Could not get color from properties
-11: Could not get margin from properties
-12: Could not get bordercolor from properties
-13: Could not get borderwidth from properties
supports only hex colors. look like css
"linear( 45deg, 0xFF0000 0%, 0xFFFF00 25%, 0x00FF00 50%, 0x00FFFF 75%, 0x0000FF, 100% )"
"linear( 45deg, 0xFF0000, 0xFFFF00, 0x00FF00, 0x00FFFF, 0x0000FF )"
"#FF0000" / "#FFF" / "#FF0000FF"
property fill:
Optional, needed for rounded buttons if you've changed the GUI background color.
Default: AHK default GUI background color
button.new(
[object/required] button gui class
[object/required] properties
)
button.new( bt, {
"normal", { ; PBS_NORMAL = 1
fill: "#fff"
background: "linear( top, #3A9CFF, #61afff )",
margin: 0,
color: "#101010",
bordercolor: "#000",
borderwidth: 0
},
"hover", { ; PBS_HOT = 2
background: "#3398FF",
margin: 0,
color: "#101010",
bordercolor: "#000",
borderwidth: 0
},
"default", { ; PBS_DEFAULTED = 5
background: "#3398FF",
margin: 0,
color: "#101010",
bordercolor: "#000",
borderwidth: 0
},
"active", { ; PBS_PRESSED = 3
background: "#3398FF",
margin: 0,
color: "#101010",
bordercolor: "#000",
borderwidth: 0
},
"disabled", { ; PBS_DISABLED = 4
background: "#3398FF",
margin: 0,
color: "#101010",
bordercolor: "#000",
borderwidth: 0
}
})
*/
class button {
static tokengp := 0
; Windows constants
static BCM_GETIMAGELIST := 0x1603
static ILC_COLOR32 := 0x020
static BS_CHECKBOX := 0x2
static BS_RADIOBUTTON := 0x4
static BS_GROUPBOX := 0x7
static BS_AUTORADIOBUTTON := 0x9
static BS_LEFT := 0x100
static BS_RIGHT := 0x200
static BS_CENTER := 0x300
static BS_TOP := 0x400
static BS_BOTTOM := 0x800
static BS_VCENTER := 0xC00
static BS_BITMAP := 0x0080
static SA_LEFT := 0x0
static SA_CENTER := 0x1
static SA_RIGHT := 0x2
static WM_GETFONT := 0x31
static IMAGE_BITMAP := 0x0
static BITSPIXEL := 0xC
static BCM_SETIMAGELIST := 0x1602
static BUTTON_IMAGELIST_ALIGN_LEFT := 0
static BUTTON_IMAGELIST_ALIGN_RIGHT := 1
static BUTTON_IMAGELIST_ALIGN_CENTER := 4
static RCBUTTONS := (
button.BS_CHECKBOX | button.BS_RADIOBUTTON | button.BS_AUTORADIOBUTTON
)
static __new() {
; Get AHK's default GUI background color
; COLOR_3DFACE is used by AHK as default
local color := dllcall( "user32\GetSysColor", "int", 15, "uint" )
this.defguicolor := (
0xFF000000 |
(( color >> 16 ) & 0xFF ) |
( color & 0x00FF00 ) |
(( color & 0xFF ) << 16 )
)
}
__new( target, properties ) {
; Check handle
if not dllcall( "user32\IsWindow", "ptr", target.hwnd ) {
msgbox( "Invalid parameter `"target`"!" )
return -1
}
; Check Options
if not isobject( properties ) {
msgbox( "Invalid parameter `"properties`"!" )
return -2
}
this.gamafix := 0
this.safe := {}
this.safe.loadedgp := false
this.safe.modulegp := dllcall( "kernel32\GetModuleHandle", "str", "gdiplus", "uptr" )
; If necessary, load the Library
if this.safe.modulegp == 0
this.safe.modulegp := dllcall( "kernel32\LoadLibrary", "str", "gdiplus.dll", "ptr" )
; If the Library is already in use
else
this.safe.loadedgp := true
if button.tokengp == 0 {
; GdiplusStartupInput structure
local input := bufferalloc( a_ptrsize == 8 ? 24 : 16, 0 )
strput( chr( 1 ), input )
local gdiptoken := 0
dllcall( "gdiplus\GdiplusStartup", "ptrp", gdiptoken, "ptr", input.ptr, "ptr", 0 )
button.tokengp := gdiptoken
varsetcapacity( gdiptoken, 0 )
; Unload class
input := "" ; varsetcapacity( input, 0 )
}
if button.tokengp == 0 {
msgbox( "GDIPlus could not be started!" )
return -3
}
; Get and check control's class and styles
this.safe.style := controlgetstyle( target.hwnd )
if ( target.type !== "Button" ) or (( this.safe.style & 0xF ^ button.BS_GROUPBOX ) == 0 ) or (( this.safe.style & button.RCBUTTONS ) > 1 ) {
button.gpshutdown( this )
msgbox( "This button does not have the required styles!" )
return -4
}
; Get the button's font
local GDIPFont := 0
local HFONT := dllcall( "user32\SendMessage", "ptr", target.hwnd, "uint", button.WM_GETFONT, "ptr", 0, "ptr", 0, "ptr" )
local DC := dllcall( "user32\GetDC", "ptr", target.hwnd, "ptr" )
dllcall( "gdi32\SelectObject", "ptr", DC, "ptr", HFONT )
dllcall( "gdiplus\GdipCreateFontFromDC", "ptr", DC, "ptrp", GDIPFont )
dllcall( "user32\ReleaseDC", "ptr", target.hwnd, "ptr", DC )
if not GDIPFont {
dllcall( "gdiplus\GdipDeleteFont", "ptr", GDIPFont )
button.gpshutdown( this )
msgbox( "Couldn't get button's font!" )
return -5
}
; else
this.font := GDIPFont
GDIPFont := ""
; varsetcapacity( GDIPFont, 0 )
; Get the button's rect
this.rect := bufferalloc( 16, 0 )
if not dllcall( "user32\GetClientRect", "ptr", target.hwnd, "ptr", this.rect.ptr ) {
this.rect := ""
button.gpshutdown( this )
msgbox( "Couldn't get button's rectangle!" )
return -6
}
this.width := numget( this.rect, 8, "int" ) - numget( this.rect, 0, "int" )
this.height := numget( this.rect, 12, "int" ) - numget( this.rect, 4, "int" )
; Create a GDI+ bitmap
local PBITMAP := 0
dllcall( "gdiplus\GdipCreateBitmapFromScan0",
"int" , this.width,
"int" , this.height,
"int" , 0,
"uint", 0x26200A,
"ptr" , 0,
"ptrp", PBITMAP
)
if not ( this.bitmap := PBITMAP ) {
button.gpshutdown( this )
msgbox( "Couldn't create the Gdiplus bitmap!" )
return -7
}
; Get the pointer to it's graphics
local PGRAPHICS := 0
dllcall( "gdiplus\GdipGetImageGraphicsContext", "ptr", PBITMAP, "ptrp", PGRAPHICS )
if not ( this.graphics := PGRAPHICS ) {
button.gpshutdown( this )
msgbox( "Couldn't create the Gdiplus bitmap!" )
return -8
}
; Quality settings
dllcall( "gdiplus\GdipSetSmoothingMode", "ptr", PGRAPHICS, "uint", 4 )
; dllcall( "gdiplus\GdipSetInterpolationMode", "ptr", PGRAPHICS, "int", 7 )
; dllcall( "gdiplus\GdipSetCompositingQuality", "ptr", PGRAPHICS, "uint", 4 )
; dllcall( "gdiplus\GdipSetRenderingOrigin", "ptr", PGRAPHICS, "int", 0, "int", 0 )
; dllcall( "gdiplus\GdipSetPixelOffsetMode", "ptr", PGRAPHICS, "uint", 4 )
; Get the button's caption
this.caption := target.text
this.hwnd := target.hwnd
this.rules := array()
if objownpropcount( properties ) {
this.rules.push( button.extract( properties, "normal" ))
this.rules.push( button.extract( properties.hasownprop( "hover" ) ? properties.hover : properties, "hover" ))
this.rules.push( button.extract( properties.hasownprop( "active" ) ? properties.active : properties, "active" ))
this.rules.push( button.extract( properties.hasownprop( "disabled" ) ? properties.disabled : properties, "disabled" ))
this.rules.push( button.extract( properties.hasownprop( "default" ) ? properties.default : properties, "default" ))
this.rules.push( this.rules[1] )
this.rules.vars := {
bordercolor: "0x00FFFFFF",
boder: max(
this.rules[1].borderwidth,
this.rules[2].borderwidth,
this.rules[3].borderwidth,
this.rules[4].borderwidth,
this.rules[5].borderwidth
)
}
button.setattributes( this )
}
}
/*
PRIVATE
*/
static setattributes( self ) {
local bitmap := []
; clear button default image
dllcall( "gdiplus\GdipGraphicsClear", "ptr", self.graphics, "uint", this.defguicolor )
local path1 := 0 ; body
local path2 := 0 ; border
local brush := 0
for property in self.rules {
; create a bitmap
local pathx := 0 + ( self.rules.vars.boder / 2 )
local pathy := 0 + ( self.rules.vars.boder / 2 )
local pathw := self.width - self.rules.vars.boder
local pathh := self.height - self.rules.vars.boder
if self.rules.vars.boder {
local pen := 0
local border := property.borderwidth || self.rules.vars.boder
local color := property.bordercolor || self.rules.vars.bordercolor
; UnitPixel = 2
dllcall( "gdiplus\GdipCreatePen1", "uint", color, "float", border, "int", 2, "uptrp", pen )
if property.borderradius > 0 {
dllcall( "gdiplus\GdipCreatePath", "uint", 0, "ptrp", path2 )
this.pathaddrect( path2, pathx, pathy, pathw, pathh, property.borderradius + ( property.borderradius / 4 ), true )
dllcall( "gdiplus\GdipDrawPath", "ptr", self.graphics, "uint", pen, "uint", path2 )
dllcall( "gdiplus\GdipDeletePath", "ptr", path2 )
}
else
dllcall( "gdiplus\GdipDrawRectangle", "ptr", self.graphics, "ptr", pen, "float", pathx, "float", pathy, "float", pathw, "float", pathh )
pathx += border / 2
pathy += border / 2
pathw -= border / 2
pathh -= border / 2
dllcall( "gdiplus\GdipDeletePen", "ptr", pen )
dllcall( "gdiplus\GdipDeletePath", "ptr", path2 )
}
if type( property.background ) == "Integer" {
dllcall( "gdiplus\GdipCreatePath", "uint", 0, "ptrp", path1 )
this.pathaddrect( path1, pathx, pathy, pathw, pathh, property.borderradius )
; create a solidbrush
dllcall( "gdiplus\GdipCreateSolidFill", "uint", property.background, "ptrp", brush )
; fill the path
dllcall( "gdiplus\GdipFillPath", "ptr", self.graphics, "ptr", brush, "ptr", path1 )
; Free resources
dllcall( "gdiplus\GdipDeleteBrush", "ptr", brush )
dllcall( "gdiplus\GdipDeletePath", "ptr", path1 )
/*
; Create a PathGradientBrush
local PBRUSH := 0
varsetcapacity( POINTS, 4 * 8, 0 )
numput( self.width - 1, POINTS, 8, "uint" )
numput( self.width - 1, POINTS, 16, "uint" )
numput( self.height - 1, POINTS, 20, "uint" )
numput( self.height - 1, POINTS, 28, "uint" )
dllcall( "gdiplus\GdipCreatePathGradientI", "ptr", &POINTS, "int", 4, "int", 0, "ptrp", PBRUSH )
; Start and target colors
; background := "0xFF" background
; Color2 := "0x00" . background
; Set the PresetBlend
varsetcapacity( COLORS, 12, 0 )
numput( property.background, COLORS, 0, "uint" )
numput( property.background, COLORS, 4, "uint" )
numput( 0, COLORS, 8, "uint" )
varsetcapacity( RELINT, 12, 0 )
numput( 0.00, RELINT, 0, "float" )
numput( 1.00, RELINT, 4, "float" )
dllcall( "gdiplus\GdipSetPathGradientPresetBlend", "ptr", PBRUSH, "ptr", &COLORS, "ptr", &RELINT, "int", 2 )
; Set the FocusScales
local DH := self.height / 2
local XScale := ( property.mode == 1 ? ( self.width - DH ) / self.width : property.mode == 2 ? 1 : 0 )
local YScale := ( property.mode == 1 ? ( self.height - DH ) / self.height : property.mode == 3 ? 1 : 0 )
dllcall( "gdiplus\GdipSetPathGradientFocusScales", "ptr", PBRUSH, "float", XScale, "float", YScale )
; Set the GammaCorrection
dllcall( "gdiplus\GdipSetPathGradientGammaCorrection", "ptr", PBRUSH, "int", self.gamafix )
; Fill button's rectangle
dllcall( "gdiplus\GdipFillRectangleI", "ptr", self.graphics, "ptr", PBRUSH, "int", 0, "int", 0, "int", self.width, "int", self.height )
; Free the brush
dllcall( "Gdiplus\GdipDeleteBrush", "ptr", PBRUSH )
*/
}
else if type( property.background ) == "Array" {
; Fill the bitmap with a linear gradient
; RECTF structure for line brush
local rect := bufferalloc( 16, 0 )
numput( self.width , rect, 8, "float" )
numput( self.height, rect, 12, "float" )
; Create a linear gradient brush with angle
; https://purebasic.developpez.com/tutoriels/gdi/documentation/GdiPlus/LinearGradientBrush/html/GdipCreateLineBrushFromRectWithAngle.html
dllcall( "gdiplus\GdipCreateLineBrushFromRectWithAngle",
"uptr" , rect.ptr,
"uint" , 0,
"uint" , 0,
"float", property.background.angle,
"int" , 1, ; Angle Scalable
"uint" , 0,
"ptrp" , brush
)
; https://purebasic.developpez.com/tutoriels/gdi/documentation/GdiPlus/LinearGradientBrush/html/GdipSetLineGammaCorrection.html
dllcall( "gdiplus\GdipSetLineGammaCorrection", "ptr", brush, "int", 1 )
local colors := bufferalloc( property.background.length * 4, 0 )
local positions := bufferalloc( property.background.length * 4, 0 )
local size := 0
for val in property.background {
numput( val.color, colors, size, "uint" )
numput( val.pos, positions, size, "float" )
size += 4
}
dllcall( "gdiplus\GdipSetLinePresetBlend", "ptr", brush, "ptr", colors.ptr, "ptr", positions.ptr, "int", property.background.length )
; dllcall( "gdiplus\GdipFillRectangle", "ptr", self.graphics, "ptr", brush, "float", 0, "float", 0, "float", self.width, "float", self.height )
dllcall( "gdiplus\GdipCreatePath", "uint", 0, "ptrp", path1 )
this.pathaddrect( path1, pathx, pathy, pathw, pathh, property.borderradius )
dllcall( "gdiplus\GdipFillPath", "ptr", self.graphics, "ptr", brush, "ptr", path1 )
; free
rect := ""
colors := ""
positions := ""
dllcall( "gdiplus\GdipDeleteBrush", "ptr", brush )
dllcall( "gdiplus\GdipDeletePath", "ptr", path1 )
}
; Create a bitmap from HBITMAP or file
else {
if type( Image ) == "Integer"
dllcall( "gdiplus\GdipCreateBitmapFromHBITMAP", "ptr", Image, "ptr", 0, "ptrp", PBM )
else
dllcall( "gdiplus\GdipCreateBitmapFromFile", "wstr", Image, "ptrp", PBM )
; Draw the bitmap
dllcall( "gdiplus\GdipDrawImageRectI", "ptr", self.graphics, "ptr", PBM, "int", 0, "int", 0, "int", self.width, "int", self.height )
; Free the bitmap
dllcall( "Gdiplus\GdipDisposeImage", "ptr", PBM )
}
; Draw the caption
local HFORMAT := 0
if ( self.caption ) {
; Create a StringFormat object
dllcall( "gdiplus\GdipCreateStringFormat", "int", 0x5404, "uint", 0, "ptrp", HFORMAT )
; Text color
local PBRUSH := 0
dllcall( "gdiplus\GdipCreateSolidFill", "uint", property.color, "ptrp", PBRUSH )
; Horizontal alignment
local HALIGN := (
( self.safe.style & this.BS_CENTER ) == this.BS_CENTER ? this.SA_CENTER
: ( self.safe.style & this.BS_CENTER ) == this.BS_RIGHT ? this.SA_RIGHT
: ( self.safe.style & this.BS_CENTER ) == this.BS_Left ? this.SA_LEFT
: this.SA_CENTER
)
dllcall( "gdiplus\GdipSetStringFormatAlign", "ptr", HFORMAT, "int", HALIGN )
; Vertical alignment
local VALIGN := (
( self.safe.style & this.BS_VCENTER ) == this.BS_TOP ? 0
: ( self.safe.style & this.BS_VCENTER ) == this.BS_BOTTOM ? 2
: 1
)
dllcall( "gdiplus\GdipSetStringFormatLineAlign", "ptr", HFORMAT, "int", VALIGN )
; Set render quality to system default
dllcall( "gdiplus\GdipSetTextRenderingHint", "ptr", self.graphics, "int", 0 )
; Set the text's rectangle
numput( 0.0, self.rect, 0, "float" )
numput( 0.0, self.rect, 4, "float" )
numput( self.width, self.rect, 8 , "float" )
numput( self.height, self.rect, 12 , "float" )
; Draw the text
dllcall( "gdiplus\GdipDrawString",
"ptr" , self.graphics,
"wstr", self.caption,
"int" , -1,
"ptr" , self.font,
"ptr" , self.rect.ptr,
"ptr" , HFORMAT,
"ptr" , PBRUSH
)
}
; Create a HBITMAP handle from the bitmap
local HBITMAP := 0
dllcall( "gdiplus\GdipCreateHBITMAPFromBitmap", "ptr", self.bitmap, "ptrp", HBITMAP, "uint", 0x00FFFFFF )
bitmap.push( HBITMAP )
; Free resources
; dllcall( "gdiplus\GdipDeleteBrush", "ptr", PBRUSH )
dllcall( "gdiplus\GdipDeleteStringFormat", "ptr", HFORMAT )
}
; Now free remaining the GDI+ objects
dllcall( "gdiplus\GdipDisposeImage", "ptr", self.bitmap )
dllcall( "gdiplus\GdipDeleteGraphics", "ptr", self.graphics )
dllcall( "gdiplus\GdipDeleteFont", "ptr", self.font )
; Create the ImageList
HIL := dllcall( "comctl32\ImageList_Create", "int", self.width, "int", self.height, "uint", this.ILC_COLOR32, "int", 6, "int", 0, "ptr" )
loop 6 {
dllcall( "comctl32\ImageList_Add", "ptr", HIL, "ptr", bitmap[ a_index ], "ptr", 0 )
; a_lasterror := 0
}
; Create a BUTTON_IMAGELIST structure
varsetcapacity( BIL, 20 + a_ptrsize, 0 )
; Get the currently assigned image list
dllcall( "user32\SendMessage", "ptr", self.hwnd, "uint", this.BCM_GETIMAGELIST, "ptr", 0, "ptr", &BIL )
local imgl := numget( BIL, "uptr" )
numput( HIL, BIL, 0, "ptr" )
numput( this.BUTTON_IMAGELIST_ALIGN_CENTER, BIL, a_ptrsize + 16, "uint" )
; Hide buttons's caption
controlsettext( "", self.hwnd )
controlsetstyle( "+" this.BS_BITMAP, self.hwnd )
; Remove the currently assigned image list, if any
if imgl
il_destroy( imgl )
; Assign the ImageList to the button
sendmessage( this.BCM_SETIMAGELIST, 0, 0, , self.hwnd )
sendmessage( this.BCM_SETIMAGELIST, 0, &BIL, , self.hwnd )
; Free the bitmaps
for index in bitmap
dllcall( "gdi32\DeleteObject", "ptr", bitmap[ a_index ])
; all done successfully
this.gpshutdown( self )
return true
}
/*
PRIVATE
*/
static gpshutdown( self ) {
}
/*
*/
static extract( properties, tipe ) {
local background := ( tipe == "hover" ? 0xFF43D4FF : 0xFF007FFF )
local color := 0xFFFFFFFF
local bordercolor := ( tipe == "hover" ? 0xFFCFCFCF : 0xFFBFBFBF )
local borderwidth := ( tipe == "hover" ? 2 : 1 )
local borderradius := 4
local margin := [ 0, 0, 0, 0 ]
; https://stackoverflow.com/questions/20215440/parse-css-gradient-rule-with-javascript-regex
if properties.hasownprop( "background" ) {
; check the background if it's just one color
if ( properties.background ~= "i)^((0x|#)?[0-9a-f]+)$" ) {
background := integer( this.gethexacolor( properties.background ))
if background == -1 {
this.gpshutdown( this )
msgbox( "Could not get background from properties!" )
return -9
}
}
; check the background for the gradient
else if ( properties.background ~= "i)^(linear(-gradient)?)" ) {
; cleaning up. remove the type from the function and remove the end of it.
background := regexreplace( properties.background , "i)^(linear(-gradient)?\s*\(\s*)|\s*\)$", "" )
; convert orientation, from to, degrees, turning or radians.
local angle := regexreplace( background, "i)^(to\s*)?((top|bottom|left|right)|[\d\.\-]+(turn|deg|rad)?).*", "$2" )
; cleaning up. remove orientation.
background := regexreplace( background, "i)^(to\s*)?((top|bottom|left|right)|[\d\.\-]+(turn|deg|rad)?)\s*,\s*", "" )
if angle ~= "deg"
angle := ( float( substr( angle, 1, -3 )) - 90 )
else if angle ~= "turn"
angle := this.turn2deg( substr( angle, 1, -4 ))
else if angle ~= "rad"
angle := this.rad2deg( substr( angle, 1, -3 ))
else if angle == "right"
angle := 0.0
else if angle == "left"
angle := 180.0
else if angle == "top"
angle := -90.0
else if angle == "bottom"
angle := 90.0
local split := strsplit( background, "," )
background := []
background.angle := angle
local safepos := [ 0.0 ]
loop split.length - 2
safepos.push(( 1.0 / ( split.length - 1 )) * a_index )
safepos.push( 1.0 )
for val in split {
local find
regexmatch( val, "i)\s*((#|0x)(?<color>[\da-f]+))((\)|\s+)(?<pos>[\.\d]+)(?<perc>%)?\s*)?", find )
local pos := ( find.pos ? ( find.pos / ( find.perc ? 100 : 0 )) : safepos[ a_index ])
if not find.color {
msgbox( "Something is wrong in the gradient color parameters." )
exitapp
}
background.push({
color: this.gethexacolor( find.color ),
pos: pos
})
}
; prevent error when starting gradient with position other than 0
if background[1].pos !== 0 {
background.insertat( 1, {
color: background[1].color,
pos: 0.0
})
}
}
}
if properties.hasownprop( "color" ) {
if ( properties.color ~= "i)^((0x|#)?[0-9a-f]+)$" ) {
color := this.gethexacolor( properties.color )
if color == -1 {
this.gpshutdown( this )
msgbox( "Could not get color from properties!" )
return -10
}
}
}
if properties.hasownprop( "margin" ) and properties.margin !== 0 {
; prevent syntax errors
local match
regexmatch(
strreplace( properties.margin, "px", "" ),
"([\d-]+)\s*([\d-]+)?\s*([\d-]+)?\s*([\d-]+)?\s*",
match
)
; margin := []
; ( match[1] !== "" ? margin.push( match[1] ) : false )
; ( match[2] !== "" ? margin.push( match[2] ) : false )
; ( match[3] !== "" ? margin.push( match[3] ) : false )
; ( match[4] !== "" ? margin.push( match[4] ) : false )
if match {
if match[2] match[3] match[4] == ""
margin := [ match[1], match[1], match[1], match[1] ]
else if match[3] match[4] == ""
margin := [ match[1], match[2], match[1], match[2] ]
else if match[4] == ""
margin := [ match[1], match[2], match[3], match[2] ]
else if match[1] !== ""
margin := [ match[1], match[2], match[3], match[4] ]
else {
this.gpshutdown( this )
msgbox( "Could not get margin from properties!" )
return -11
}
}
}
if properties.hasownprop( "bordercolor" ) {
if ( bordercolor ~= "i)^((0x|#)?[0-9a-f]+)$" ) {
bordercolor := this.gethexacolor( bordercolor )
if bordercolor == -1 {
this.gpshutdown( this )
msgbox( "Could not get bordercolor from properties!" )
return -12
}
}
}
if properties.hasownprop( "borderwidth" ) and not properties.borderwidth ~= "(none|0)" {
; prevent syntax errors
local match
regexmatch(
strreplace( properties.borderwidth, "px", "" ),
"([\d-]+)\s*([\d-]+)?\s*([\d-]+)?\s*([\d-]+)?\s*",
match
)
if match {
if match[2] match[3] match[4] == ""
borderwidth := [ match[1], match[1], match[1], match[1] ]
else if match[3] match[4] == ""
borderwidth := [ match[1], match[2], match[1], match[2] ]
else if match[4] == ""
borderwidth := [ match[1], match[2], match[3], match[2] ]
else if match[1] !== ""
borderwidth := [ match[1], match[2], match[3], match[4] ]
else {
this.gpshutdown( this )
msgbox( "Could not get borderwidth from properties!" )
return -13
}
}
}
if properties.hasownprop( "borderradius" ) and not properties.borderradius ~= "^(\s*(none|)\s*)$" {
borderradius := properties.borderradius
}
return {
"background" : background,
"bordercolor" : bordercolor ? bordercolor : "",
"borderwidth" : borderwidth,
"borderradius": borderradius,
"margin" : margin,
"color" : color
}
}
/*
PRIVATE
*/
static gethexacolor( color ) {
color := regexreplace( color, "^#", "" )
local length := strlen( color )
if length == 6
return integer( "0xFF" strupper( color ))
if length == 8
return integer( "0x" strupper( substr( color, 7, 2 ) substr( color, 1, 6 )))
if length == 3 or length == 4
return integer( "0x" strupper(
( length == 4 ? substr( color, 4, 1 ) substr( color, 4, 1 ) : "FF" )
substr( color, 1, 1 ) substr( color, 1, 1 )
substr( color, 2, 1 ) substr( color, 2, 1 )
substr( color, 3, 1 ) substr( color, 3, 1 )
))
if length == 10
return color
; error
else
return -1
}
/*
PRIVATE
*/
static pathaddrect( path, left, top, width, height, radius := 0, draft := false ) {
if radius < 1 {
; for body
return dllcall( "gdiplus\GdipAddPathRectangle",
"ptr" , path,
"float", left,
"float", top,
"float", width,
"float", height
)
}
local D := ( radius * 2 )
width -= D
height -= D
; top left arc
dllcall( "gdiplus\GdipAddPathArc",
"ptr" , path,
"float", left,
"float", top,
"float", D,
"float", D,
"float", 180,
"float", 90
)
; top right arc
dllcall( "gdiplus\GdipAddPathArc",
"ptr" , path,
"float", width,
"float", top,
"float", D,
"float", D,
"float", 270,
"float", 90
)
; bottom right line
dllcall( "gdiplus\GdipAddPathArc",
"ptr" , path,
"float", width,
"float", height,
"float", D,
"float", D,
"float", 0,
"float", 90
)
; bottom left arc
dllcall( "gdiplus\GdipAddPathArc",
"ptr" , path,
"float", left,
"float", height,
"float", D,
"float", D,
"float", 90,
"float", 90
)
return dllcall( "gdiplus\GdipClosePathFigure", "ptr", path )
}
/*
PRIVATE
PI: 3.14159265359
*/
static rad2deg( rad ) => ( round( rad * 180 / 3.14159265359, 2 ) - 90.0 )
; static rad2turn( rad ) => round(( rad * 180 / 3.14159265359 ) / 360, 2 )
; static rad2perc( rad ) => round(( 100 * ( rad * 180 / 3.14159265359 )) / 360, 2 )
; static deg2rad( deg ) => deg * ( 3.14159265359 / 180 )
; static deg2perc( deg ) => ( 100 * deg ) / 360
; static deg2turn( deg ) => ( deg / 360 )
; static turn2rad( turn ) => dllcall( "msvcrt\atan2", "double", turn, "double", 0, "cdecl double" )
; static turn2perc( turn ) => float( turn * 100 )
static turn2deg( turn ) => (( 360 / 100 ) * ( turn * 100 ) - 90.0 )
}
fm := guicreate( "", "Image Buttons" )
fm.marginx := 50
fm.marginy := 20
fm.setfont( "s10" )
bt := fm.addbutton( "vBT2 h30 w200", "Button" )
fm.addbutton( "YP h30 w200", "Button" )
bt.setfont( "", "Verdana" )
button.new( bt, {
background: "linear( top, #3A9CFF, #61afff )",
hover: { background: "linear( top, #FF0000 10%, #FFFF00 25%, #00FF00 50%, #00FFFF 75%, #0000FF 100% )" },
active: { background: "#43D4FF" }
})
fm.show( "x10 y10" )
- hoppfrosch
- Posts: 443
- Joined: 07 Oct 2013, 04:05
- Location: Rhine-Maine-Area, Hesse, Germany
- Contact:
Re: [Class] ImageButton - 1.5.00.00 - 20201230
Which AHK V2 version? Tried it with V2.0-a138 and there were errors ...F4Jonatas wrote: ↑18 Jul 2021, 07:52First I did it for AHK v2 and I'm adding other things, for example more gradient, support gradient angle and transparency on the edges and background.
Re: [Class] ImageButton - 1.5.00.00 - 20201230
@F4Jonatas: Move your script to AutoHotkey v2 Scripts and Functions, please. I don't intend do do anything with v2 before a beta will be released.
If you want I'll provide a link in the OP.
If you want I'll provide a link in the OP.
Re: [Class] ImageButton - 1.5.00.00 - 20201230
I added 2 comments in my script
Code: Select all
; for v1.5 add UseGDIP.ahk or Include them into Class_ImageButton.ahk
; #Include UseGDIP.ahk
[AHK] v2.0.5 | [WIN] 11 Pro (Version 22H2) | [GitHub] Profile
Re: [Class] ImageButton - 1.5.00.00 - 20201230
@just me I just wanted to show you that we can add more stuff. But if you want I move my post.
hoppfrosch I'm using a version: 2.0-a108-a2fa0498
hoppfrosch I'm using a version: 2.0-a108-a2fa0498
-
- Posts: 7
- Joined: 09 Apr 2021, 05:57
Re: [Class] ImageButton - 1.5.00.00 - 20201230
If you use the Create method of the ImageButton class again, the text disappears.
Re: [Class] ImageButton - 1.5.00.00 - 20201230
just me wrote: ↑17 May 2021, 07:15@c7aesa7r,
because of problems on Win XP (and maybe later versions) the class containsto remove the button's caption. You might try to comment it out.Code: Select all
; Hide buttons's caption ControlSetText, , , ahk_id %HWND%
-
- Posts: 2
- Joined: 13 Apr 2022, 13:14
Re: [Class] ImageButton - 1.5.00.00 - 20201230
Is there any way to do hover effect more smoothly? cuz its cool but honestly looks kinda 5 fpsjust me wrote: ↑22 Dec 2013, 10:28Prior version at old forum -> /board/topic/75064-function-createimagebutton-ahk-l/
Caution: Update 1.5.00.00 contains script breaking changes! Please read the change history.
Also, it is barely tested and may contain bugs!
Well, here's a new version of an old script of mine. It has become more up-to-date than ever, because it can be 'misused' for somewhat 'Metro styled' buttons.
ImageButton_1_3.png
Change HistoryLook at GitHub!
Download from GitHub!
Note: To run the sample script, download both script files from the Sources folder and both pic files from Resources and store them all together into one folder. The script files should be saved as UTF-8 with BOM.
Other Samples
Re: [Class] ImageButton - 1.5.00.00 - 20201230
hello, just me:
Is it possible to make the button highlighted immediately when the mouse is over it. It is now about 100ms before the button is highlighted.
Is it possible to make the button highlighted immediately when the mouse is over it. It is now about 100ms before the button is highlighted.
Re: [Class] ImageButton - 1.5.00.00 - 20201230
All timings are controlled by the OS.
Re: [Class] ImageButton - 1.5.00.00 - 20201230
@just me Thanks for your reply, I found the solution:
viewtopic.php?t=27743
Code: Select all
#SingleInstance, Force
#NoEnv
DisableFadeEffect()
gui, font, s10
gui, add, Button, w200, 确定
gui, show, w300 center, test01
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)
}
}
esc::ExitApp
Re: [Class] ImageButton - 1.5.00.00 - 20201230
Hello just me,
How i can increase the blue color in this button. I do not want the gradient to be 50% between the two colors.
I want to specify which color should be bigger than the other color, Is this possible?
How i can increase the blue color in this button. I do not want the gradient to be 50% between the two colors.
I want to specify which color should be bigger than the other color, Is this possible?
Code: Select all
#NoEnv
SetBatchLines, -1
Gradients := [["0xFFFFFF", "0x009dff"], ["0xFFD8F029", "0xFFAABD20"], ["0xFFF011AA", "0xFFBD0D85"]
, ["0xFF29F08D", "0xFF20BD70"], ["0xFFA027F5", "0xFF7A1EBD"]]
Buttons := [1]
NumOfBtns := Buttons.Length()
BtnsPerRow := 4
BtnW := "w160"
BtnH := "h45"
GuiColor := "White"
TxtColor := "White"
Gui, Margin, 3, 3
Gui, Font, s12
Gui, Color, %GuiColor%
ImageButton.SetGuiColor(GuiColor)
BtnNum := 0
While (BtnNum < NumOfBtns) {
Loop, %BtnsPerRow% {
BtnNum++
Gradient := Gradients[Buttons[BtnNum]]
Opt1 := [3, Gradient[1], Gradient[2], "White", 5]
BtnX := A_Index = 1 ? "xm" : "x+m"
Gui, Add, Button, %BtnX% %BtnW% %BtnH% vBtn%BtnNum% gBtnClicked hwndHBTN, Button %BtnNum%
If !ImageButton.Create(HBTn, Opt1) {
}
} Until (BtnNum >= NumOfBtns)
}
Gui, Show, , Gradient Buttons
Return
GuiClose:
GuiEscape:
ExitApp
BtnClicked:
Gui, +OwnDialogs
MsgBox, 0, Click!, You clicked on button %A_GuiControl%!
Return
#Include <UseGDIP>
#Include <Class_ImageButton>
Re: [Class] ImageButton - 1.5.00.00 - 20201230
As far as I know, it is not currently possible with the class. You have only one start and one finish color here.
@just me would have to adapt the class so that more than 2 colors can be passed. Similar to https://github.com/AHK-just-me/LinearGradient/blob/master/Sources/LinearGradient.ahk
@just me would have to adapt the class so that more than 2 colors can be passed. Similar to https://github.com/AHK-just-me/LinearGradient/blob/master/Sources/LinearGradient.ahk
[AHK] v2.0.5 | [WIN] 11 Pro (Version 22H2) | [GitHub] Profile
Re: [Class] ImageButton - 1.5.00.00 - 20201230
@HiSoKa - Perhaps this will give you a result close to what you want. Run the script with your current gradient and use the Window Spy tool to grab a color part-way through the gradient displayed on the button, then use that as the new start end of the gradient instead of 0xFFFFFF. So you would get a resulting gradient to use something like this: ["0xD7E9FF", "0x009dff"]
Re: [Class] ImageButton - 1.5.00.00 - 20201230
Thanks @jNizM and @just me I will take a look there..
Thanks You @boiler This is exactly what I intended to do, And now I got the desired result ,
Thank you so much to point it out
Thanks You @boiler This is exactly what I intended to do, And now I got the desired result ,
Thank you so much to point it out
Re: [Class] ImageButton - 1.5.00.00 - 20201230
Hi, @just me .
Sorry for the inconvenience again,
But I'm having a problem and I'm wondering if you have a solution.
My problem is that I want to use WS_EX_LAYOUTRTL for writing style, Because the Arabic language is from right to left That's way sometimes some problems appear when writing in Arabic, and this style solves this problem.
My problem is when I apply it to [Class] ImageButton, it completely reverses the characters. Is there a solution to this problem?
And thank you in advance
Sorry for the inconvenience again,
But I'm having a problem and I'm wondering if you have a solution.
My problem is that I want to use WS_EX_LAYOUTRTL for writing style, Because the Arabic language is from right to left That's way sometimes some problems appear when writing in Arabic, and this style solves this problem.
My problem is when I apply it to [Class] ImageButton, it completely reverses the characters. Is there a solution to this problem?
And thank you in advance
Code: Select all
#NoEnv
SetBatchLines, -1
Gui, Font, s12
Loop, 1 {
Gradient := ["0xA020F0", "0xD7A1F9"]
Opt1 := [3, Gradient[1], Gradient[2], "White", 5]
Gui, Add, Button, w160 h45 hwndHBTN +E0x00400000, Hello World!!
If !ImageButton.Create(HBTn, Opt1) {
}
}
Gui, Show, , Gradient Buttons
Return
GuiClose:
GuiEscape:
ExitApp
#Include <UseGDIP>
#Include <Class_ImageButton>
ESC::ExitApp
Re: [Class] ImageButton - 1.5.00.00 - 20201230
Hi, I cannot test it.
The image button doesn't have a caption. Apparently, the bitmap is just mirrored.
If I create a common button with this style and the caption text "Hello World!!" it results in "!!Hello World".WS_EX_LAYOUTRTL wrote:If the shell language is Hebrew, Arabic, or another language that supports reading order alignment, the horizontal origin of the window is on the right edge. Increasing horizontal values advance to the left.
The image button doesn't have a caption. Apparently, the bitmap is just mirrored.