(Solved)Making any program(window) click-through

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
coolykoen
Posts: 61
Joined: 01 Jun 2015, 06:10

(Solved)Making any program(window) click-through

08 Jun 2015, 03:25

is it possible to make any window click-trhough, like, lets say i have a calculator, and it is alwaysontop, id like to be able to make that calculator clicktrhough (for example with a hotkey)
is this possible?

thanks for any help / answers :)
Last edited by coolykoen on 05 Feb 2016, 05:23, edited 1 time in total.
User avatar
dangerdogL2121
Posts: 173
Joined: 01 Oct 2013, 23:11

Re: Making any program(window) click-through

11 Jun 2015, 01:23

It is possible!

I made a little example.

Code: Select all

#Persistent
WinTitle = Calculator ;or whatever you want
SetTitleMatchMode, 2
FallThrough = 1
WinSet, ExStyle, +0x20, % WinTitle ; 0x20 = WS_EX_CLICKTHROUGH
WinSet, Transparent, 100, % WinTitle ; for convinience, but you can take this out
WinSet, AlwaysOnTop, On, % WinTitle
return

e::
if FallThrough = 1
{
	FallThrough = 0
	WinSet, ExStyle, -0x20, % WinTitle
	WinSet, Transparent, 255, % WinTitle
	WinSet, AlwaysOnTop, Off, % WinTitle
}
else
{
	FallThrough = 1
	WinSet, ExStyle, +0x20, % WinTitle
	WinSet, Transparent, 100, % WinTitle
	WinSet, AlwaysOnTop, On, % WinTitle
}
return
Hope it helps. ;)
coolykoen
Posts: 61
Joined: 01 Jun 2015, 06:10

Re: Making any program(window) click-through

05 Feb 2016, 05:22

dangerdogL2121 wrote:
Hope it helps. ;)
YES thank you so much, didnt think it would be this easy :)

EDIT: sorry for the late reaction, but i do have one more question: how can i revert the window to NOT be clicktrough?
Turbo-dog

Re: (Solved)Making any program(window) click-through

18 Dec 2017, 08:48

To revert the window reverse the action on it with another script
Example:

Where you're enabling click-through script has:
"WinSet, ExStyle, +0x20, % WinTitle"

you would set your click-through disabling script as:
"WinSet, ExStyle, -0x20, % WinTitle"

...hope this helps.
The_One_True_Rick
Posts: 65
Joined: 25 May 2023, 17:14

Re: (Solved)Making any program(window) click-through

10 Oct 2023, 22:54

Anyone know how to passthrough mouse hover? this seems to be working great for clicks but my mouse hover is still getting caught up on the top gui and not being passed through to the bottom gui.
User avatar
Hellbent
Posts: 2109
Joined: 23 Sep 2017, 13:34

Re: (Solved)Making any program(window) click-through

11 Oct 2023, 04:22

Likely a "active window" issue.
If you set "+0x20" to the active window it's still the active window until it's not.

***Edit***
Confirmed.
The_One_True_Rick
Posts: 65
Joined: 25 May 2023, 17:14

Re: (Solved)Making any program(window) click-through

11 Oct 2023, 14:19

Here is some more info for the issue I am having. I made these custom buttons to change color out of stacked text box, progress bar, and blank picture for the g label. Here is part of the class that makes the button.

Code: Select all

		Gui, %Bottom_GUI%: Add, Picture, % "W" W " H" H " X" X " Y" Y " v" This.Number " BackgroundTrans hwndhwnd g" Label " 0xE"
		Handles[hwnd] := "Open_Custom_Button_Menu"
		Gui, %Bottom_GUI%: Add, Progress, % "W" W " H" H " X" X " Y" Y " c" Button_Color " BackgroundBlack hwndhwnd Border v" This.Prog_Var, 100
		this.hwnd := hwnd
		Gui, %Top_GUI%: Font, s%Font_Size% bold c%Font_Color%
		Gui, %Top_GUI%: Add, Text, % "W" W " H" H " X" X " Y" Y " v" Button_Name " Center BackgroundTrans", % Text
I have the bottom gui as the parent of the top one. I keep the text on the top transparent gui so I can change the color of the progress bar without redrawing it every time which cuts down on the flashing. The clicks to activate the button work just fine but the button hover function only works on the top of the button because the text control hwnd is getting in the way.

Code: Select all

Button_Hover(){
    Static Index , Hover_On
    MouseGetPos,,,, ctrl , 2
	;GuiControlGet, OutputVar, Name , % ctrl
	;ToolTip, % OutputVar
    if( ! Hover_On && ctrl ){
        loop , % Custom_Buttons.Length()
			if (ctrl = Custom_Buttons[A_Index].hwnd)
                Custom_Buttons[A_Index].Hover_Animation() , Index := A_Index , Hover_On := 1 , break
    }else if( Hover_On = 1 )
        if (ctrl != Custom_Buttons[Index].hwnd)
            Custom_Buttons[Index].Button_Color_Manager() , Hover_On := 0
}
I can post more code if necessary. I think it has something to do with the order I drew the controls in since it works just fine if I remove the parent/child relationship but I would prefer to keep that.
User avatar
Hellbent
Posts: 2109
Joined: 23 Sep 2017, 13:34

Re: (Solved)Making any program(window) click-through

11 Oct 2023, 18:18

There is no need to use two guis to create that effect.

Add your buttons and then add your picture control last with this option +0x4000000 WS_CLIPSIBLINGS

Here is an example. You don't need to change all your code to be exactly like mine, just see how it works and make a few changes to your script.

.
clipsibling.gif
clipsibling.gif (50.24 KiB) Viewed 1317 times
.

Code: Select all

#SingleInstance, Force
SetBatchLines, -1

Gui1 := {}
Gui, New, +AlwaysOnTop hwndhwnd
Gui1.Hwnd := hwnd
Gui, Margin, 10 , 10
Gui, Add, Progress, xm ym w100 h30 BackgroundBlack cRed Disabled hwndhwnd, 100
Gui1.ProgressHwnd := hwnd
Gui, Add, Text, xm ym w100 h30 BackgroundTrans Center 0x200 gTestLabel hwndhwnd, Sample
Gui1.TextHwnd := hwnd
Gui, Margin, 0 , 0
Gui, Add, Picture, xm ym w300 h300 +0x4000000 , ImageFile.png
Gui, Show


OnMessage( 0x200 , Func( "WatchCursor" ).Bind( Gui1 ) )
return

GuiClose:
GuiContextMenu:
*ESC::ExitApp

TestLabel:
	SoundBeep
	return
	
WatchCursor( Gui1 ){  
	MouseGetPos,,,, ctrl , 2
	if( ctrl = Gui1.TextHwnd ){
		GuiControl, +c0099ff , % Gui1.ProgressHwnd
		GuiControl, +Redraw, % Gui1.TextHwnd
	}
	
}
***Edit*** I just noticed that you mentioned the flicker issue as being the reason for using two guis.
If you are on windows 8+ you can use gdip and a child layered window and you won't have any issues with flicker.
I'll see if I can come up with a solution to your current setup tomorrow if I have time.
The_One_True_Rick
Posts: 65
Joined: 25 May 2023, 17:14

Re: (Solved)Making any program(window) click-through

11 Oct 2023, 21:43

Oh wow that’s awesome. Thanks! I’ll play around with it. Yeah the redraw was causing flicker because I have about 20 color changing buttons that change to red to show what active window I’m on , green if the window exists, and red if the window does not exists so whenever the active window changes or a new window is created it loops over all the buttons and changes to their corresponding color which on the 2 layers looks seamless but when redrawing all the controls makes then blink. Got that working preset good by only changing the color of the buttons that needed color changing but then that gave me problems when I added in the button hover thing so here we are haha.
Last edited by The_One_True_Rick on 11 Oct 2023, 21:55, edited 1 time in total.
The_One_True_Rick
Posts: 65
Joined: 25 May 2023, 17:14

Re: (Solved)Making any program(window) click-through

11 Oct 2023, 21:49

Yeah I tried the gdip thing a little bit. Kind of got it working but was still getting some flickering issue. I’ll try again when I get some more time. I’m sure I just had something wrong. Just need to put some more time into learning gdip and aside of this little hover issue progress bars are working just fine for me haha.
The_One_True_Rick
Posts: 65
Joined: 25 May 2023, 17:14

Re: (Solved)Making any program(window) click-through

11 Oct 2023, 21:59

A good way to center 2 line text on a progress bar would also help. My text boxes are not exactly lined up with the progress bar so I can simulate the text being centered on the progress bar so on half the button you are hovering over the button so the hover works but on the second half of the button you are over the text box so it doesn’t work. If they lined up exactly then I could just look for hand of the text box instead instead of the progress bar.
User avatar
Hellbent
Posts: 2109
Joined: 23 Sep 2017, 13:34

Re: (Solved)Making any program(window) click-through

12 Oct 2023, 10:25

The_One_True_Rick wrote:
11 Oct 2023, 21:59
Yeah I tried the gdip thing a little bit. Kind of got it working but was still getting some flickering issue. I’ll try again when I get some more time. I’m sure I just had something wrong. Just need to put some more time into learning gdip and aside of this little hover issue progress bars are working just fine for me haha.
Here is an example of using gdip ( WINDOWS 8+ )
You can use as many buttons as you want and never have flickering.

.
child Layered window buttons  2.gif
child Layered window buttons 2.gif (865.07 KiB) Viewed 1197 times
.
20231012114403.png
20231012114403.png (330.14 KiB) Viewed 1189 times
.


Main Script

Code: Select all

;****************************************************************************************************************************************************************************
#Include <My Altered GDIP lib> ;GDIP_ALL:  https://www.autohotkey.com/boards/viewtopic.php?f=6&t=6517
#Include <PopUpWindow_V2> ;Found in the other code box. (save it as its own file or paste it at the bottom of the script and remove this line)
;****************************************************************************************************************************************************************************
#SingleInstance, Force
SetBatchLines, -1
Gdip_Startup()

;&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&

;Main window object
Gui1 := {}

;&&&&&&&&&&&&&&&&&&

;this shows how you can create a bitmap of the background image from a file
;~ Gui1.BackgroundBitmap := Gdip_CreateBitmapFromFile( "ImageFile.png" )

;&&&&&&&&&&&&&&&&&&

;you can also use a picture control on the main gui. Just make sure to add the picture control after the button window is added

;&&&&&&&&&&&&&&&&&&
;(FOR DEMO)
;this creates a bitmap for the background from a base 64 string
;(FOR DEMO)
bgB64 := "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"
Gui1.BackgroundBitmap := B64ToPBitmap( bgB64 )
;&&&&&&&&&&&&&&&&&&

;set the size of the main window
Gui1.W := 1000
Gui1.H := 600

;set the position of the window
Gui1.X := ( A_ScreenWidth - Gui1.W ) / 2
Gui1.Y := ( A_ScreenHeight - Gui1.H ) / 2

;create a new ahk gui
Gui, New, +AlwaysOnTop hwndhwnd

;store the hwnd of the window in the gui1 object
Gui1.Hwnd := hwnd

;show the window without actually showing it (this allows you to add all the buttons before showing the window ) 
Gui, Show, % "Hide x" Gui1.X " y" Gui1.Y " w" Gui1.W " h" Gui1.H 

;&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&

;Create the inner layered child window
Gui1.ButtonWindow := New PopUpWindow( { AutoShow: 1 , X: 0 , Y: 0 , W: Gui1.W , H: Gui1.H , Options: " -DPIScale +Parent" Gui1.Hwnd } ) 

;create the button objects
Gui1.ButtonWindow.Buttons := {}
Gui1.ButtonWindow.ButtonHandles := []

;a list of colors for the demo
Colors := [ "0xFFEE1F11" , "0xFFEE5B11" , "0xFFF37C0C" , "0xFFEED111" , "0xFFC8F30C" , "0xFF78F30C" , "0xFF46F30C" , "0xFF14F30C" , "0xFF11EE44" , "0xFF15EA98" , "0xFF15EAE3" , "0xFF15C7EA" , "0xFF118EEE" , "0xFF083CF7" , "0xFF2F0CF3" , "0xFF7411EE" , "0xFF9A0CF3" , "0xFFB90CF3" ]

;a list of alpha values for the demo
hexList := [ "FF" , "EE" , "DD" , "CC" , "BB" , "AA" , "99" , "88" , "77" , "66" , "55" , "44" , "33" , "22" , "11" , "00" ]

;set the y position for the first button
y := 10

;the current amount of buttons
Index := 0

;loop the y axis
Loop, 10	{
	
	;set the x position for the first button on each row
	x := 10
	
	;set a variable with the current outer loop index
	outerIndex := A_Index + 3
	
	;loop the x axis ( determind by the length of the color list for the demo )
	Loop, % Colors.Length()	{
		;increment the current button count by 1 
		Index++
		
		;create a temp object to pass to the custom button constructor ( only values that are changing from the default button values need to be added )
		tempButtonObj := {	 X: 			x
							,Y: 			y
							,W:				50				
							,H:				50				
							,Text:			"Sample`n" Index		
							,FontColor: 	"0xFFFFFFFF"
							,DefaultColor: 	"0x" hexList[ outerIndex ] SubStr( colors[ A_Index ] , 5 ) 
							,HoverColor: 	"0x" hexList[ outerIndex ] SubStr( colors[ Random( 1 , colors.Length() ) ] , 5 ) 
							,Label:			"TestLabel"
							,UseGradient: 	Random( 0 , 1 ) 
							,Roundness:		Random( 0 , 10 ) } 
		
		;create a new custom button
		Gui1.ButtonWindow.Buttons[ "Button_" Index ] := New CustomButton( Gui1.ButtonWindow.Hwnd , tempButtonObj )
		
		;add a key / value to store the index of the button
		Gui1.ButtonWindow.Buttons[ "Button_" Index ].Index := Index
		
		;add a key / value to store the Name of the button
		Gui1.ButtonWindow.Buttons[ "Button_" Index ].ButtonName := "Button_" Index
		
		;use the buttons handle as an index in an array
		Gui1.ButtonWindow.ButtonHandles[ Gui1.ButtonWindow.Buttons[ "Button_" Index ].Hwnd ] := Gui1.ButtonWindow.Buttons[ "Button_" Index ]
		
		;change the x postion for the next button
		x += tempButtonObj.W + 5
	}
	;change the y position for the next row of buttons
	y += tempButtonObj.H + 10
}


;&&&&&&&&&&&&&&&&&&

;example of using a picture control on the main window instead of drawing the background on the button window.
;~ Gui, % Gui1.hwnd ":Add", Picture, % "x" 0 " y" 0 " w" Gui1.W " h" Gui1.H  , ImageFile.png

;&&&&&&&&&&&&&&&&&&

;draw all the buttons onto the button inner layered window.
DrawButtons( Gui1 )

;Show the window now that everything has been added to it
Gui, % Gui1.Hwnd ":Show", % "x" Gui1.X " y" Gui1.Y " w" Gui1.W " h" Gui1.H 

OnMessage( 0x200 , func( "WatchCursor" ).bind( Gui1 ) ) ;hover function demo

;end of auto-exectue section
return

;exit routine
GuiClose:
GuiContextMenu:
*ESC::ExitApp

;*********************************************************************************************************************************************************************
;generic test label (all the buttons are set to call this label when they are clicked in this demo)
TestLabel:	;{

	;Get the hwnd of the control under the cursor
	MouseGetPos,,,, ctrl , 2 
	
	;increment the buttons current state ( Default , Hover , Pressed , Disabled ) FOR DEMO PURPOSES
	( ++Gui1.ButtonWindow.ButtonHandles[ ctrl ].CurrentState > 4 ) ? ( Gui1.ButtonWindow.ButtonHandles[ ctrl ].CurrentState := 1 )
	
	;display a tooltip with the name and the current state of the button you clicked
	ToolTip, % "Button Name:	" Gui1.ButtonWindow.ButtonHandles[ ctrl ].ButtonName "`nCurrent State:	" Gui1.ButtonWindow.ButtonHandles[ ctrl ].CurrentState
	
	;Draw the button window
	DrawButtons( Gui1 )
	
	;set a timer to turn off the tooltip
	SetTimer, TipOff, -1000
	
	;end of rountine
	return
;}

;*********************************************************************************************************************************************************************

;Demo hover function (FOR DEMO)
WatchCursor( Gui1 ){
	MouseGetPos,,,, ctrl , 2
	ToolTip, % "Button Name:	" Gui1.ButtonWindow.ButtonHandles[ ctrl ].ButtonName "`nCurrent State:	" Gui1.ButtonWindow.ButtonHandles[ ctrl ].CurrentState
}

;*********************************************************************************************************************************************************************

;routine to remove any tooltips (FOR DEMO)
TipOff:	;{
	ToolTip
	return
;}

;*********************************************************************************************************************************************************************

;hotkey to set the state of every button to a random value between 1 and 4 and then draw the button window. (FOR DEMO)
F1::	;{
	ChangeStatesDemo( Gui1 )
	return
;}

;*********************************************************************************************************************************************************************

;change the state of all buttons (FOR DEMO)
ChangeStatesDemo( Gui1 ){
	static tog := 0
	Tog := !Tog 
	for k , v in Gui1.ButtonWindow.Buttons	{
		Gui1.ButtonWindow.Buttons[ k ].CurrentState := Random( 1 , 4 )
	}
	DrawButtons( Gui1 )
}

;*********************************************************************************************************************************************************************

;random number function (FOR DEMO)
Random( Min := 0 , Max := 100 ){
	local out
	Random, out , Min , Max
	return out
}

;*********************************************************************************************************************************************************************

;function to redraw all the buttons on the button window in their current states
DrawButtons( Gui1 ){
	;a list of all the button states
	static stateList := [ "Default" , "Hover" , "Pressed" , "Disabled" ]
	
	;clear the graphics of the button window
	Gui1.ButtonWindow.ClearWindow()
	
	;Paint the background of the button window (FOR DEMO)
	Gui1.ButtonWindow.PaintBackground( color := "0xFF000000" , AutoUpdate := 0 ) ;{ Color: "0xFF000000" , X: 2 , Y: 2 , W: Gui1.ButtonWindow.W - 4 , H: Gui1.ButtonWindow.H - 4 } , Round: 10 }
	
	;draw the background image on the button window (FOR DEMO)
	Gui1.ButtonWindow.DrawBitmap( Gui1.BackgroundBitmap , { X: 0 , Y: 0 , W: Gui1.ButtonWindow.W , H: Gui1.ButtonWindow.H } , 0 , 0 )
	
	;loop through all of the buttons
	for k , v in Gui1.ButtonWindow.Buttons	{
		
		;shorten the name of the current button
		cc := Gui1.ButtonWindow.Buttons[ k ] 
		
		;get the state of the button
		state := stateList[ cc.CurrentState ]
		
		;get the pointer for the current button
		bitmap := cc[ state "Bitmap" ]
		
		;draw the current button in its current state onto the graphics of the button window without updating the windows appearance yet
		Gui1.ButtonWindow.DrawBitmap( bitmap , cc , 0 , 0 )
	}
	
	;update the appearance of the button window
	Gui1.ButtonWindow.UpdateWindow()
}

;*********************************************************************************************************************************************************************
;class to create instances of the button objects. 
;this includes creating a trigger ( adding a gui text control to the buttons window )
;it also includes creating a bitmap for each of the current 4 different states ( Default , Hover , Pressed , Disabled )

class CustomButton	{
	
	
	;###############################################################################################
	
	;create a new button
	__New( Parent , obj := "" ){
		
		;set the parent window ( the button window hwnd )
		This.Parent := parent
		
		;set the default values that a button starts off with.
		This._SetDefaults()
		
		;update the values with the new values you supply (if any)
		This._UpdateDefaults( obj )
		
		;add the text control to the parent window so that labels can be triggered by clicking
		;and so that a hwnd can be detected for a hover function.
		This._CreateControl()
		
		;take the values and create a bitmap for each state for this button.
		This._CreateBitmaps()
		
	}
	
	;###############################################################################################
	
	;set all the default values.
	_SetDefaults(){
		This.X 					:= 10
		This.Y					:= 10
		This.W 					:= 100
		This.H 					:= 20
		This.Text 				:= ""
		This.FontType			:= "Segoe UI"
		This.FontSize			:= 12
		This.FontColor			:= "0xFF000000"
		This.FontOptions		:= " Center vCenter Bold NoWrap"
		This.FontOffsetX		:= 1
		This.FontOffsetY		:= 1
		This.DefaultColor		:= "0xFF32363a"
		This.HoverColor			:= "0xFF00FF00"
		This.PressedColor		:= "0xFFFF0000"
		This.DisabledColor		:= "0xFF777777"
		This.UseGradient		:= 1
		This.GradientColor		:= "0xFF000000"
		This.CurrentState		:= 1
		This.Smoothing 			:= 2
		This.Roundness			:= 0
		This.BorderColor		:= "0xFF000000"
		This.BorderThickness 	:= 2
		
	}
	
	;###############################################################################################
	
	;update values
	_UpdateDefaults( obj := "" ){
		if( IsObject( obj ) ){
			for k , v in obj
				This[ k ] := obj[ k ]
		}
	}
	
	;###############################################################################################
	
	;add the text control (trigger [click,hover,etc])
	_CreateControl(){
		if( This.Label ){
			Gui, % This.Parent ":Add", Text, % "x" This.X " y" This.Y " w" This.W " h" This.H " hwndhwnd g" This.Label
			
		}else{
			Gui, % This.Parent ":Add", Text, % "x" This.X " y" This.Y " w" This.W " h" This.H " hwndhwnd"
		}
		This.Hwnd := hwnd
	}
	
	;###############################################################################################
	
	;create a bitmap for each button state
	_CreateBitmaps(){
		
		;a list of all the current states
		static stateList := [ "Default" , "Hover" , "Pressed" , "Disabled" ]
		
		;loop through all the states
		for k , v in stateList	{
			
			;create a new bitmap for the current state (the canvas to be drawn to for the current state)
			This[ v "Bitmap" ] := Gdip_CreateBitmap( This.W , This.H )
			G := Gdip_GraphicsFromImage( This[ v "Bitmap" ] )
			Gdip_SetSmoothingMode( G , This.Smoothing )
			
			;check if a gradient should be applied
			if( !This.UseGradient )
				
				;create a solid brush with the current states color
				Brush := Gdip_BrushCreateSolid( This[ v "Color" ] )
			else
				;create a gradient brush with the current states color and the gradient color
				Brush := Gdip_CreateLineBrushFromRect( 0 , 0 , This.W , This.H , This[ v "Color" ] , This.GradientColor )
			
			;use the brush to fill a rounded rectangle. (the buttons main surface)
			Gdip_FillRoundedRectangle( G , Brush , 1 , 1 , This.W - 2 , This.H - 2 , This.Roundness )
			
			;delete the brush to free the memory ( *pointers )
			Gdip_DeleteBrush( Brush )
			
			;check if gradient should be used
			if( !This.UseGradient ){
				
				;create a solid pen
				Pen := Gdip_CreatePen( This.BorderColor , This.BorderWidth )
				
			}else{
				
				;create a gradient brush
				Brush := Gdip_CreateLineBrushFromRect( 0 , 0 , This.W , This.H , This[ v "Color" ] , This.GradientColor )
				
				;create a pen from the brush
				Pen := Gdip_CreatePenFromBrush( Brush , w)
				
				;delete the brush to free the memory
				Gdip_DeleteBrush( Brush )
			}
			
			;draw a rounded rectangle. (Border around the button)
			Gdip_DrawRoundedRectangle( G , Pen , 1 , 1 , This.W - 2 , This.H - 2 , This.Roundness )
			
			;delete the pen to free memory
			Gdip_DeletePen( Pen )
			
			
			;create a brush to paint the text with.
			Brush := Gdip_BrushCreateSolid( This.FontColor )
			
			;draw the text onto the bitmap
			Gdip_TextToGraphics( G , This.Text , "s" This.FontSize " c" Brush " " This.FontOptions " x" 1 + This.FontOffsetX " y" 1 + This.FontOffsetY  , This.FontType , This.W - 2 , This.H - 2 )
			
			;delete the brush to free memory
			Gdip_DeleteBrush( Brush )
			
			;delete the grahics object to free memory
			Gdip_DeleteGraphics( G )
		}
	}
}

;###############################################################################################

;function to convert a Base 64 string into a pBitmap (FOR DEMO)
B64ToPBitmap( Input ){
	local ptr , uptr , pBitmap , pStream , hData , pData , Dec , DecLen , B64
	VarSetCapacity( B64 , strlen( Input ) << !!A_IsUnicode )
	B64 := Input
	If !DllCall("Crypt32.dll\CryptStringToBinary" ( ( A_IsUnicode ) ? ( "W" ) : ( "A" ) ), Ptr := A_PtrSize ? "Ptr" : "UInt" , &B64, "UInt", 0, "UInt", 0x01, Ptr, 0, "UIntP", DecLen, Ptr, 0, Ptr, 0)
		Return False
	VarSetCapacity( Dec , DecLen , 0 )
	If !DllCall("Crypt32.dll\CryptStringToBinary" (A_IsUnicode ? "W" : "A"), Ptr, &B64, "UInt", 0, "UInt", 0x01, Ptr, &Dec, "UIntP", DecLen, Ptr, 0, Ptr, 0)
		Return False
	DllCall("Kernel32.dll\RtlMoveMemory", Ptr, pData := DllCall("Kernel32.dll\GlobalLock", Ptr, hData := DllCall( "Kernel32.dll\GlobalAlloc", "UInt", 2,  UPtr := A_PtrSize ? "UPtr" : "UInt" , DecLen, UPtr), UPtr) , Ptr, &Dec, UPtr, DecLen)
	DllCall("Kernel32.dll\GlobalUnlock", Ptr, hData)
	DllCall("Ole32.dll\CreateStreamOnHGlobal", Ptr, hData, "Int", True, Ptr "P", pStream)
	DllCall("Gdiplus.dll\GdipCreateBitmapFromStream",  Ptr, pStream, Ptr "P", pBitmap)
	return pBitmap
}
Layered window class

Code: Select all

;####################################################################################################################################################################################
;####################################################################################################################################################################################
;####################################################################################################################################################################################
;####################################################################################################################################################################################
class PopUpWindow	{
;PopUpWindow v2.2
;Date Written: Oct 28th, 2021
;Last Edit: Feb 7th, 2022 :Changed the trigger method.
;Written By: Hellbent aka CivReborn
;SpcThanks: teadrinker , malcev 
	static Index := 0 , Windows := [] , Handles := [] , EditHwnd , HelperHwnd
	__New( obj := "" ){
		This._SetDefaults()
		This.UpdateSettings( obj )
		This._CreateWindow()
		This._CreateWindowGraphics()
		if( This.AutoShow )
			This.ShowWindow( This.Title )
	}
	_SetDefaults(){
		This.X := 10
		This.Y := 10
		This.W := 10
		This.H := 10
		This.Smoothing := 2
		This.Options := " -DPIScale +AlwaysOnTop "
		This.AutoShow := 0
		This.GdipStartUp := 0
		This.Title := ""
		
		This.Controls := []
		This.Handles := []
		This.Index := 0 
	}
	AddTrigger( obj ){
		local k , v , cc , bd
		
		This.Controls[ ++This.Index ] := { 	X:		10
										,	Y:		10
										,	W:		10
										,	H:		10	}
		for k, v in obj
			This.Controls[ This.Index ][ k ] := obj[ k ] 
		cc := This.Controls[ This.Index ]
		Gui, % This.Hwnd ":Add", Text, % "x" cc.X " y" cc.Y " w" cc.W " h" cc.H " hwndhwnd"
		This.Handles[ hwnd ] := This.Index
		This.Controls[ This.Index ].Hwnd := hwnd
		
		if( IsObject( cc.Label ) ){
			bd := cc.Label
			GuiControl, % This.Hwnd ":+G" , % hwnd , % bd
		}else{
			bd := This._TriggerCall.Bind( This )
			GuiControl, % This.Hwnd ":+G" , % hwnd , % bd
		}
		return hwnd
		
	}
	_TriggerCall(){
		MouseGetPos,,,, ctrl, 2
		Try
			;~ SetTimer, % This.Controls[ This.Handles[ ctrl ] ].Label, -0
			gosub, % This.Controls[ This.Handles[ ctrl ] ].Label
		
				
	}
	DrawTriggers( color := "0xFFFF0000" , AutoUpdate := 0 ){
		local brush , cc 
		Brush := Gdip_BrushCreateSolid( color ) 
		Gdip_SetSmoothingMode( This.G , 3 )
		loop, % This.Controls.Length()	{
			cc := This.Controls[ A_Index ]
			Gdip_FillRectangle( This.G , Brush , cc.x , cc.y , cc.w , cc.h )
		
		}
		Gdip_DeleteBrush( Brush )
		Gdip_SetSmoothingMode( This.G , This.Smoothing )
		if( AutoUpdate )
			This.UpdateWindow()
	}
	UpdateSettings( obj := "" , UpdateGraphics := 0 ){
		local k , v
		if( IsObject( obj ) )
			for k, v in obj
				This[ k ] := obj[ k ]
		( This.X = "Center" ) ? ( This.X := ( A_ScreenWidth - This.W ) / 2 ) 	
		( This.Y = "Center" ) ? ( This.Y := ( A_ScreenHeight - This.H ) / 2 ) 	
		if( UpdateGraphics ){
			This._DestroyWindowsGraphics()
			This._CreateWindowGraphics()
		}
	}
	_CreateWindow(){
		local hwnd
		Gui , New, % " +LastFound +E0x80000 hwndhwnd -Caption  " This.Options
		PopUpWindow.Index++
		This.Index := PopUpWindow.Index
		PopUpWindow.Windows[ PopUpWindow.Index ] := This
		This.Hwnd := hwnd
		PopUpWindow.Handles[ hwnd ] := PopUpWindow.Index
		if( This.GdipStartUp && !PopUpWindow.pToken )
			PopUpWindow.pToken := GDIP_STARTUP()
	}
	_DestroyWindowsGraphics(){
		Gdip_DeleteGraphics( This.G )
		SelectObject( This.hdc , This.obm )
		DeleteObject( This.hbm )
		DeleteDC( This.hdc )
	}
	_CreateWindowGraphics(){
		This.hbm := CreateDIBSection( This.W , This.H )
		This.hdc := CreateCompatibleDC()
		This.obm := SelectObject( This.hdc , This.hbm )
		This.G := Gdip_GraphicsFromHDC( This.hdc )
		Gdip_SetSmoothingMode( This.G , This.Smoothing )
	}
	ShowWindow( Title := "" ){
		Gui , % This.Hwnd ":Show", % "x" This.X " y" This.Y " w" This.W " h" This.H " NA", % Title
	}
	HideWindow(){
		Gui , % This.Hwnd ":Hide",
	}
	UpdateWindow( alpha := 255 ){
		UpdateLayeredWindow( This.hwnd , This.hdc , This.X , This.Y , This.W , This.H , alpha )
	}
	ClearWindow( AutoUpdate := 0 , Color := "" ){
		if( color != "" )
			Gdip_GraphicsClear( This.G , color )
		else
			Gdip_GraphicsClear( This.G )
		if( Autoupdate )
			This.UpdateWindow()
	}
	DrawBitmap( pBitmap , obj , dispose := 1 , AutoUpdate := 0 ){
		Gdip_DrawImage( This.G , pBitmap , obj.X , obj.Y , obj.W , obj.H )
		if( dispose )
			Gdip_DisposeImage( pBitmap )
		if( Autoupdate )
			This.UpdateWindow()
	}
	PaintBackground( color := "0xFF000000" , AutoUpdate := 0 ){
		if( isObject( color ) ){
			Brush := Gdip_BrushCreateSolid( ( color.HasKey( "Color" ) ) ? ( color.Color ) : ( "0xFF000000" ) ) 
			if( color.Haskey( "Round" ) )
				Gdip_FillRoundedRectangle( This.G , Brush , color.X , color.Y , color.W , color.H , color.Round )
			else
				Gdip_FillRectangle( This.G , Brush , color.X , color.Y , color.W , color.H ) 
		}else{
			Brush := Gdip_BrushCreateSolid( color ) 
			Gdip_FillRectangle( This.G , Brush , -1 , -1 , This.W + 2 , This.H + 2 ) 
		}
		Gdip_DeleteBrush( Brush )
		if( AutoUpdate )
			This.UpdateWindow()
	}
	DeleteWindow( GDIPShutdown := 0 ){
		Gui, % This.Hwnd ":Destroy"
		SelectObject( This.hdc , This.obm )
		DeleteObject( This.hbm )
		DeleteDC( This.hdc )
		Gdip_DeleteGraphics( This.G )
		hwnd := This.Hwnd
		for k, v in PopUpWindow.Windows[ Hwnd ]
			This[k] := ""
		PopUpWindow.Windows[ Hwnd ] := ""
		if( GDIPShutdown ){
			Gdip_Shutdown( PopUpWindow.pToken )
			PopUpWindow.pToken := ""
		}
	}
	_OnClose( wParam ){
		if( wParam = 0xF060 ){	;SC_CLOSE ;[ clicking on the gui close button ]
			Try{
				Gui, % PopUpWindow.HelperHwnd ":Destroy"
				SoundBeep, 555
			}
		}
	}
	CreateCachedBitmap( pBitmap , Dispose := 0 ){
		local pCachedBitmap
		if( This.CachedBitmap )
			This.DisposeCachedbitmap()
		DllCall( "gdiplus\GdipCreateCachedBitmap" , "Ptr" , pBitmap , "Ptr" , this.G , "PtrP" , pCachedBitmap )
		This.CachedBitmap := pCachedBitmap
		if( Dispose )
			Gdip_DisposeImage( pBitmap )
	}
	DrawCachedBitmap( AutoUpdate := 0 ){
		DllCall( "gdiplus\GdipDrawCachedBitmap" , "Ptr" , this.G , "Ptr" , This.CachedBitmap , "Int" , 0 , "Int" , 0 )
		if( AutoUpdate )
			This.UpdateWindow()
	}
	DisposeCachedbitmap(){
		DllCall( "gdiplus\GdipDeleteCachedBitmap" , "Ptr" , This.CachedBitmap )
	}
	Helper(){
		local hwnd , MethodList := ["__New","UpdateSettings","ShowWindow","HideWindow","UpdateWindow","ClearWindow","DrawBitmap","PaintBackground","DeleteWindow" , "AddTrigger" , "DrawTriggers", "CreateCachedBitmap" , "DrawCachedBitmap" , "DisposeCachedbitmap" ]
		Gui, New, +AlwaysOnTop +ToolWindow +HwndHwnd
		PopUpWindow.HelperHwnd := hwnd
		Gui, Add, Edit, xm ym w250 r1 Center hwndhwnd, Gui1
		PopUpWindow.EditHwnd := hwnd
		loop, % MethodList.Length()	
			Gui, Add, Button, xm y+1 w250 r1 gPopUpWindow._HelperClip, % MethodList[ A_Index ]
		Gui, Show,,
		OnMessage( 0x112 , This._OnClose.Bind( hwnd ) )
	}
	_HelperClip(){
		local ClipList 
		
		GuiControlGet, out, % PopUpWindow.HelperHwnd ":", % PopUpWindow.EditHwnd	
		
		ClipList := 		{ 	__New: 					" := New PopUpWindow( { AutoShow: 1 , X: 0 , Y: 0 , W: A_ScreenWidth , H: A_ScreenHeight , Options: "" -DPIScale +AlwaysOnTop "" } )"
							,	UpdateSettings:			".UpdateSettings( { X: """" , Y: """" , W: """" , H: """" } , UpdateGraphics := 0 )"
							,	ShowWindow:				".ShowWindow( Title := """" )"
							,	HideWindow:				".HideWindow()"
							,	UpdateWindow:			".UpdateWindow()"
							,	ClearWindow:			".ClearWindow( AutoUpdate := 0 )"
							,	DrawBitmap:				".DrawBitmap( pBitmap := """" , { X: 0 , Y: 0 , W: " Out ".W , H: " Out ".H } , dispose := 1 , AutoUpdate := 0 )"
							,	PaintBackground:		".PaintBackground( color := ""0xFF000000"" , AutoUpdate := 0 )  "  ";{ Color: ""0xFF000000"" , X: 2 , Y: 2 , W: " Out ".W - 4 , H: " Out ".H - 4 , Round: 10 }"
							,	DeleteWindow:			".DeleteWindow( GDIPShutdown := 0 )"
							,	AddTrigger:				".AddTrigger( { X: """" , Y: """" , W: """" , H: """" , Value: """" , Label: """" } )"	
							,	DrawTriggers:			".DrawTriggers( color := ""0xFFFF0000"" , AutoUpdate := 0 )"	
							,	CreateCachedBitmap:		".CreateCachedBitmap( pBitmap , Dispose := 0 )"	
							,	DrawCachedBitmap: 		".DrawCachedBitmap( AutoUpdate := 0 )"	
							,	DisposeCachedbitmap:	".DisposeCachedbitmap()"	}
							
		clipboard := Out ClipList[ A_GuiControl ]
		
	}
}




The_One_True_Rick wrote:
11 Oct 2023, 21:59
A good way to center 2 line text on a progress bar would also help. My text boxes are not exactly lined up with the progress bar so I can simulate the text being centered on the progress bar so on half the button you are hovering over the button so the hover works but on the second half of the button you are over the text box so it doesn’t work. If they lined up exactly then I could just look for hand of the text box instead instead of the progress bar.
You can use rows as the way you set your height.

The way I would do it is create a dummy control with its height set in rows h200 vs. r4 ( using all the same font options )

Code: Select all

Gui, DummyGui:Add, Text, r4 , mytext
Next I would get the position/size of the dummy control using GuiControl, pos, DummyGui:pos , static1
Now that I have the size I can destroy the window object that was created when the control was created
Lastly the size can be used for the width and height of the button.

when you display your text you can format it for new lines.

Code: Select all

MyText := "`nSample`nText"
Last edited by Hellbent on 12 Oct 2023, 10:45, edited 1 time in total.
The_One_True_Rick
Posts: 65
Joined: 25 May 2023, 17:14

Re: (Solved)Making any program(window) click-through

12 Oct 2023, 10:35

Thanks I'll give all that a try. Thanks for all the videos too. They are very helpful!
The_One_True_Rick
Posts: 65
Joined: 25 May 2023, 17:14

Re: (Solved)Making any program(window) click-through

12 Oct 2023, 15:31

OK I managed to get it mostly working with GDIP. Still getting the occasional flicker of the button but I'm sure i just have something wrong. Still need to practice with GDIP but here is the general idea I'm going for.

Code: Select all

#SingleInstance,Force
SetBatchLines, -1
SetTitleMatchMode, RegEx

global HB_Button:=[]
;-----------------------------------------------------------------------------------------------------------------------------------------------------
SetTimer, HB_Button_Hover , 50
SetTimer, HB_Window_Active , 50
;-----------------------------------------------------------------------------------------------------------------------------------------------------
OnMessage(0x0201, "Drag_GUI")
;-----------------------------------------------------------------------------------------------------------------------------------------------------

pToken := Gdip_Startup()
JustTheBasics()

gui, 1: +alwaysontop -DPIScale +E0x08000000
HB_Button.Push( New Custom_Button(x := 30 , y := 30 , w := 150 , h := 40 , Button_Color := "FED1E6", Text := "Craft of Exile", Font := "Arial", Font_Size := 16, Font_Color := "000000", Window := "1", Label := "Custom_Button.Button_Label", Window_Title := "Craft of Exile - Google Chrome", URL := "Chrome.exe https://www.craftofexile.com/ --new-window"))
HB_Button.Push( New Custom_Button(x := 30 , y := 80 , w := 150 , h := 40 , Button_Color := "FED1E6", Text := "Trade", Font := "Arial", Font_Size := 16, Font_Color := "000000", Window := "1", Label := "Custom_Button.Button_Label", Window_Title := "Trade.*- Google Chrome", URL := "Chrome.exe https://www.pathofexile.com/trade/search/Metamorph --new-window"))
HB_Button.Push( New Custom_Button(x := 30 , y := 130 , w := 150 , h := 40 , Button_Color := "FED1E6", Text := "Currency", Font := "Arial", Font_Size := 16, Font_Color := "000000", Window := "1", Label := "Custom_Button.Button_Label", Window_Title := "Currency - Crucible - poe.ninja - Google Chrome", URL := "Chrome.exe https://poe.ninja/economy/challenge/currency --new-window"))
HB_Button.Push( New Custom_Button(x := 30 , y := 180 , w := 150 , h := 40 , Button_Color := "FED1E6", Text := "PoE DB", Font := "Arial", Font_Size := 16, Font_Color := "000000", Window := "1", Label := "Custom_Button.Button_Label", Window_Title := "Modifiers - PoEDB, Path of Exile Wiki - Google Chrome", URL := "Chrome.exe https://poedb.tw/us/Modifiers --new-window"))
HB_Button.Push( New Custom_Button(x := 30 , y := 230 , w := 150 , h := 40 , Button_Color := "FED1E6", Text := "Forum", Font := "Arial", Font_Size := 16, Font_Color := "000000", Window := "1", Label := "Custom_Button.Button_Label", Window_Title := "Forum -.*- Google Chrome", URL := "Chrome.exe https://www.pathofexile.com/forum --new-window"))
gui, 1: color, Black
gui, 1: show, w220 h300 NA, POE Window Manager

gui, 2: +Parent1 -Caption +LastFound +E0x80000 -DPIScale
gui, 2: show, x10 y10 w200 h280 NA,
return

;-----------------------------------------------------------------------------------------------------------------------------------------------------
;	Button Class
;-----------------------------------------------------------------------------------------------------------------------------------------------------

class Custom_Button {
    __New(x := 10 , y := 10 , w := 150 , h := 40 , Button_Color := "FF0000", Text := "Button" , Font := "Arial" , Font_Size := 16 , Font_Color := "FFFFFF" , Window := "1" , Label := "Custom_Button.Button_Label", Window_Title := "NA", URL := "NA"){
	    This.Font_Color := "0xFF" Font_Color
        This.Font := Font
        This.Font_Size := Font_Size
        This.Text := Text
        This.X := x
        This.Y := y
        This.W := w
        This.H := h
        This.Window := Window
        This.Label := Label
		This.URL := URL

        This.Create_Default()
		This.Create_Window_Exists_Bitmap()
		This.Create_Window_Not_Exists_Bitmap()
		This.Create_Window_Active_Bitmap()
        This.Create_Hover_Bitmap()
        This.Create_Pressed_Bitmap()
        This.Create_Trigger()
        sleep, 20

		This.Window_ID := WinExist(Window_Title)

		if WinActive("ahk_id " This.Window_ID)
			This.Draw_Window_Active()
		else if WinExist(Window_Title)
			This.Draw_Window_Exists()
		else{
			This.Draw_Window_Not_Exists()
			This.Window_ID := ""
		}

    }
    Create_Trigger(){
        global
        num := HB_Button.Length()+1
        Gui , % This.Window ": Add" , Picture , % "x" This.X " y" This.Y " w" This.W " h" This.H " hwndHwnd v" Num " g" This.Label " 0xE"
        This.Number := Num , This.Hwnd := Hwnd
    }
    Create_Default(){
        pBitmap:=Gdip_CreateBitmap( This.W , This.H ) ;96x29
		G := Gdip_GraphicsFromImage( pBitmap )
        Gdip_SetSmoothingMode( G , 2 )

		Brush := Gdip_BrushCreateSolid(This.Button_Color)
		Gdip_FillRectangle(G, Brush, -1 , -1 , This.W+2 , This.H+2 )
		Gdip_DeleteBrush(Brush)

        Brush := Gdip_BrushCreateSolid( This.Font_Color )
        Gdip_TextToGraphics( G , This.Text , "s" This.Font_Size " Bold Center vCenter c" Brush " x1 y2 " , This.Font , This.W , This.H-1 )
        Gdip_DeleteBrush( Brush )

		Gdip_DeleteGraphics( G )
        This.Default_Bitmap := Gdip_CreateHBITMAPFromBitmap(pBitmap)
        Gdip_DisposeImage(pBitmap)
    }
    Create_Hover_Bitmap(){
        ;Bitmap Created Using: HB Bitmap Maker
        pBitmap:=Gdip_CreateBitmap( This.W , This.H ) ;96x29
		G := Gdip_GraphicsFromImage( pBitmap )
        Gdip_SetSmoothingMode( G , 2 )

        Brush := Gdip_BrushCreateSolid( This.Hover_Color )
        Gdip_FillRectangle( G , Brush , -1 , -1 , This.W+2 , This.H+2 )
        Gdip_DeleteBrush( Brush )

        Brush := Gdip_BrushCreateSolid( This.Font_Color )
        Gdip_TextToGraphics( G , This.Text , "s" This.Font_Size " Bold Center vCenter c" Brush " x1 y2" , This.Font , This.W , This.H-1 )
        Gdip_DeleteBrush( Brush )

        Gdip_DeleteGraphics( G )
        This.Hover_Bitmap := Gdip_CreateHBITMAPFromBitmap(pBitmap)
        Gdip_DisposeImage(pBitmap)
    }
	Create_Window_Active_Bitmap(){
		pBitmap:=Gdip_CreateBitmap( This.W , This.H )
		G := Gdip_GraphicsFromImage( pBitmap )
        Gdip_SetSmoothingMode( G , 2 )

        Brush := Gdip_BrushCreateSolid("0xFFFF6363")
        Gdip_FillRectangle( G , Brush , -1 , -1 , This.W+2 , This.H+2 )
        Gdip_DeleteBrush( Brush )

        Brush := Gdip_BrushCreateSolid( This.Font_Color )
        Gdip_TextToGraphics( G , This.Text , "s" This.Font_Size " Bold Center vCenter c" Brush " x1 y2" , This.Font , This.W , This.H-1 )
        Gdip_DeleteBrush( Brush )

        Gdip_DeleteGraphics( G )
        This.Window_Active_Bitmap := Gdip_CreateHBITMAPFromBitmap( pBitmap )
        Gdip_DisposeImage( pBitmap )
	}
	Create_Window_Not_Exists_Bitmap(){
		pBitmap:=Gdip_CreateBitmap( This.W , This.H )
		G := Gdip_GraphicsFromImage( pBitmap )
        Gdip_SetSmoothingMode( G , 2 )

        Brush := Gdip_BrushCreateSolid("0xFFFED1E6")
        Gdip_FillRectangle( G , Brush , -1 , -1 , This.W+2 , This.H+2 )
        Gdip_DeleteBrush( Brush )

        Brush := Gdip_BrushCreateSolid( This.Font_Color )
        Gdip_TextToGraphics( G , This.Text , "s" This.Font_Size " Bold Center vCenter c" Brush " x1 y2" , This.Font , This.W , This.H-1 )
        Gdip_DeleteBrush( Brush )

        Gdip_DeleteGraphics( G )
        This.Window_Not_Exists_Bitmap := Gdip_CreateHBITMAPFromBitmap( pBitmap )
        Gdip_DisposeImage( pBitmap )
	}
	Create_Window_Exists_Bitmap(){
		pBitmap:=Gdip_CreateBitmap( This.W , This.H )
		G := Gdip_GraphicsFromImage( pBitmap )
        Gdip_SetSmoothingMode( G , 2 )

        Brush := Gdip_BrushCreateSolid("0xFFBBDBB8")
        Gdip_FillRectangle( G , Brush , -1 , -1 , This.W+2 , This.H+2 )
        Gdip_DeleteBrush( Brush )

        Brush := Gdip_BrushCreateSolid( This.Font_Color )
        Gdip_TextToGraphics( G , This.Text , "s" This.Font_Size " Bold Center vCenter c" Brush " x1 y2" , This.Font , This.W , This.H-1 )
        Gdip_DeleteBrush( Brush )

        Gdip_DeleteGraphics( G )
        This.Window_Exists_Bitmap := Gdip_CreateHBITMAPFromBitmap( pBitmap )
        Gdip_DisposeImage( pBitmap )
	}
    Create_Pressed_Bitmap(){
        pBitmap:=Gdip_CreateBitmap( This.W , This.H )
		G := Gdip_GraphicsFromImage( pBitmap )
        Gdip_SetSmoothingMode( G , 2 )

        Brush := Gdip_BrushCreateSolid( This.Pressed_Color )
        Gdip_FillRectangle( G , Brush , -1 , -1 , This.W+2 , This.H+2 )
        Gdip_DeleteBrush( Brush )

        Brush := Gdip_BrushCreateSolid( This.Font_Color )
        Gdip_TextToGraphics( G , This.Text , "s" This.Font_Size " Bold Center vCenter c" Brush " x1 y4" , This.Font , This.W , This.H-1 )
        Gdip_DeleteBrush( Brush )

        Gdip_DeleteGraphics( G )
        This.Pressed_Bitmap := Gdip_CreateHBITMAPFromBitmap( pBitmap )
        Gdip_DisposeImage( pBitmap )
    }
    Draw_Default(){
        SetImage( This.Hwnd , This.Default_Bitmap )
		This.Create_Hover_Bitmap()
		This.Create_Pressed_Bitmap()
    }
    Draw_Hover(){
        SetImage( This.Hwnd , This.Hover_Bitmap )
    }
	Draw_Window_Exists(){
		SetImage( This.Hwnd , This.Window_Exists_Bitmap )
		This.Button_Color := "0xFFBBDBB8"
		This.Hover_Color := "0xFF" Format("{:X}", LightenDarkenColor("BBDBB8", -10))
		This.Pressed_Color := "0xFF" Format("{:X}", LightenDarkenColor("BBDBB8", -50))
		This.Create_Default()
		This.Create_Hover_Bitmap()
		This.Create_Pressed_Bitmap()
	}
	Draw_Window_Not_Exists(){
		SetImage( This.Hwnd , This.Window_Not_Exists_Bitmap )
		This.Button_Color := "0xFFFED1E6"
		This.Hover_Color := "0xFF" Format("{:X}", LightenDarkenColor("FED1E6", -10))
		This.Pressed_Color := "0xFF" Format("{:X}", LightenDarkenColor("FED1E6", -50))
		This.Create_Default()
		This.Create_Hover_Bitmap()
		This.Create_Pressed_Bitmap()
	}
	Draw_Window_Active(){
		SetImage( This.Hwnd , This.Window_Active_Bitmap )
		This.Button_Color := "0xFFFF6363"
		This.Hover_Color := "0xFF" Format("{:X}", LightenDarkenColor("FF6363", -10))
		This.Pressed_Color := "0xFF" Format("{:X}", LightenDarkenColor("FF6363", -50))
		This.Create_Default()
		This.Create_Hover_Bitmap()
		This.Create_Pressed_Bitmap()
	}
    Draw_Pressed(){
        SetImage( This.Hwnd , This.Pressed_Bitmap )
        SetTimer , HB_Button_Hover , Off
        While( GetKeyState( "LButton" ) )
            sleep , 10
        SetTimer , HB_Button_Hover , On
        MouseGetPos,,,, ctrl , 2
        if( This.Hwnd != ctrl ){
            This.Draw_Default()
            return False
        }else{
            This.Draw_Hover()
            return true
        }
    }
	Button_Label(){
	Critical, On
	GuiControl , % HB_Button[A_GuiControl].Window ": Focus" , % HB_Button[A_GuiControl].Hwnd
	if( ! HB_Button[A_GuiControl].Draw_Pressed() ){
		Critical, Off
		return
	}

	if WinExist("ahk_id " HB_Button[A_GuiControl].Window_ID){
		WinActivate, % "ahk_id" HB_Button[A_GuiControl].Window_ID
		Critical, Off
		return
	}

	if !WinExist("ahk_exe chrome.exe"){
		Run, Chrome.exe "https://www.autohotkey.com/" " --new-window " " --start-maximized" --profile-directory="Default",, Hide
		WinWaitActive, ahk_exe Chrome.*,, 3  ;leave above as run, its breaks as runwait for some reason
		Sleep, 100
		WinGet, Restored_Session_Tabs, ID, A
	}

	Browser_IDs := {}
	WinGet, Browser_ID_List, List, ahk_exe ((msedge|chrome).exe)
	loop, % Browser_ID_List
		Browser_IDs[Browser_ID_List%A_Index%] := 1
	RunWait, % HB_Button[A_GuiControl].URL " --start-maximized " "--profile-directory=Default"
	loop {
		Sleep, 50
		WinWaitActive, ahk_exe chrome.exe
	} until  !Browser_IDs.HasKey(New_Window := WinExist("A"))
	Critical, Off

	HB_Button[A_GuiControl].Window_ID := New_Window

	Browser_IDs := ""
	Sleep, 100

	WinClose, ahk_id %Restored_Session_Tabs%
	}
}


HB_Window_Active(){
    Static Index , Active_On
	Win := WinExist("A")
    if( ! Active_On && Win ){
        loop , % HB_Button.Length()
            if( Win = HB_Button[ A_Index ].Window_ID )
                HB_Button[ A_Index ].Draw_Window_Active() , Index := A_Index , Active_On := 1 , break
    }
	else if( Active_On = 1 ){
        if( Win != HB_Button[ Index ].Window_ID ){
			Active_On := 0
			Switch {
				Case WinActive("ahk_id " HB_Button[ Index ].Window_ID) : HB_Button[ Index ].Draw_Window_Active()
				Case WinExist("ahk_id " HB_Button[ Index ].Window_ID) : HB_Button[ Index ].Draw_Window_Exists()
				Default: HB_Button[ Index ].Draw_Window_Not_Exists()
			}
		}
	}
}


HB_Button_Hover(){
    Static Index , Hover_On
    MouseGetPos,,,, ctrl , 2
    if( ! Hover_On && ctrl ){
        loop , % HB_Button.Length()
            if( ctrl = HB_Button[ A_Index ].hwnd )
                HB_Button[ A_Index ].Draw_Hover() , Index := A_Index , Hover_On := 1 , break
    }else if( Hover_On = 1 )
        if( ctrl != HB_Button[ Index ].Hwnd )
            HB_Button[ Index ].Draw_Default() , Hover_On := 0
}

LightenDarkenColor(Color, Amount){
	Hex_Color := "0x" Color
	r := (Hex_Color >> 16) + Amount
	b := ((Hex_Color >> 8) & 0x00FF) + Amount
	g := (Hex_Color & 0x0000FF) + Amount
	newColor := g | (b << 8) | (r << 16)
	return newColor
}

Drag_GUI(){
	if A_GuiControl
		return
	PostMessage 0xA1, 2
}

;-----------------------------------------------------------------------------------------------------------------------------------------------------
;	GDIP Helper Functions
;-----------------------------------------------------------------------------------------------------------------------------------------------------

JustTheBasics() {
	global

	; Start gdi+
	If !pToken := Gdip_Startup(){
		MsgBox, 48, gdiplus error!, Gdiplus failed to start. Please ensure you have gdiplus on your system
		ExitApp
	}
	OnExit, Exit
	return


	Exit:
	; gdi+ may now be shutdown on exiting the program
	Gdip_Shutdown(pToken)
	ExitApp
	Return

}

StartDrawGDIP(){
	global
	hbm := CreateDIBSection(480, 480) ; Create a bitmap with W and H of what we are going to draw into it. This is the entire drawing area for everything
	hdc := CreateCompatibleDC()  		   ; Get a device context compatible with the screen
	obm := SelectObject(hdc, hbm)          ; Select the bitmap into the device context
	G := Gdip_GraphicsFromHDC(hdc)         ; Get a pointer to the graphics of the bitmap, for use with drawing functions
}

EndDrawGDIP(){
	global
	; Update the specified window we have created (hwnd1) with a handle to our bitmap (hdc), specifying the x,y,w,h we want it positioned on our screen
	; So this will position our gui at (0,0) with the Width and Height specified earlier
	UpdateLayeredWindow(hwnd1, hdc)
	SelectObject(hdc, obm)  ; Select the object back into the hdc
	DeleteObject(hbm)       ; Now the bitmap may be deleted
	DeleteDC(hdc)           ; Also the device context related to the bitmap may be deleted
	Gdip_DeleteGraphics(G)  ; The graphics may now be deleted
}

ClearDrawGDIP() {
	global
	Gdip_GraphicsClear(G)
}

;-----------------------------------------------------------------------------------------------------------------------------------------------------
;					GDIP Other Functions
;-----------------------------------------------------------------------------------------------------------------------------------------------------

Gdip_Shutdown(pToken){
    Ptr := A_PtrSize ? "UPtr" : "UInt"

    DllCall("gdiplus\GdiplusShutdown", Ptr, pToken)
    if hModule := DllCall("GetModuleHandle", "str", "gdiplus", Ptr)
        DllCall("FreeLibrary", Ptr, hModule)
    return 0
}

;-----------------------------------------------------------------------------------------------------------------------------------------------------
;					GDIP Functions
;-----------------------------------------------------------------------------------------------------------------------------------------------------


BitBlt(ddc, dx, dy, dw, dh, sdc, sx, sy, Raster=""){
    Ptr := A_PtrSize ? "UPtr" : "UInt"
    return DllCall("gdi32\BitBlt", Ptr, dDC, "int", dx, "int", dy, "int", dw, "int", dh, Ptr, sDC, "int", sx, "int", sy, "uint", Raster ? Raster : 0x00CC0020)
}
Gdip_DrawImage(pGraphics, pBitmap, dx="", dy="", dw="", dh="", sx="", sy="", sw="", sh="", Matrix=1){
    Ptr := A_PtrSize ? "UPtr" : "UInt"
    if (Matrix&1 = "")
        ImageAttr := Gdip_SetImageAttributesColorMatrix(Matrix)
    else if (Matrix != 1)
        ImageAttr := Gdip_SetImageAttributesColorMatrix("1|0|0|0|0|0|1|0|0|0|0|0|1|0|0|0|0|0|" Matrix "|0|0|0|0|0|1")
    if(sx = "" && sy = "" && sw = "" && sh = ""){
        if(dx = "" && dy = "" && dw = "" && dh = ""){
            sx := dx := 0, sy := dy := 0
            sw := dw := Gdip_GetImageWidth(pBitmap)
            sh := dh := Gdip_GetImageHeight(pBitmap)
        }else   {
            sx := sy := 0,sw := Gdip_GetImageWidth(pBitmap),sh := Gdip_GetImageHeight(pBitmap)
        }
    }
    E := DllCall("gdiplus\GdipDrawImageRectRect", Ptr, pGraphics, Ptr, pBitmap, "float", dx, "float", dy, "float", dw, "float", dh, "float", sx, "float", sy, "float", sw, "float", sh, "int", 2, Ptr, ImageAttr, Ptr, 0, Ptr, 0)
    if ImageAttr
        Gdip_DisposeImageAttributes(ImageAttr)
    return E
}
Gdip_SetImageAttributesColorMatrix(Matrix){
    Ptr := A_PtrSize ? "UPtr" : "UInt"
    VarSetCapacity(ColourMatrix, 100, 0)
    Matrix := RegExReplace(RegExReplace(Matrix, "^[^\d-\.]+([\d\.])", "$1", "", 1), "[^\d-\.]+", "|")
    StringSplit, Matrix, Matrix, |
    Loop, 25
    {
        Matrix := (Matrix%A_Index% != "") ? Matrix%A_Index% : Mod(A_Index-1, 6) ? 0 : 1
        NumPut(Matrix, ColourMatrix, (A_Index-1)*4, "float")
    }
    DllCall("gdiplus\GdipCreateImageAttributes", A_PtrSize ? "UPtr*" : "uint*", ImageAttr)
    DllCall("gdiplus\GdipSetImageAttributesColorMatrix", Ptr, ImageAttr, "int", 1, "int", 1, Ptr, &ColourMatrix, Ptr, 0, "int", 0)
    return ImageAttr
}
Gdip_GetImageWidth(pBitmap){
   DllCall("gdiplus\GdipGetImageWidth", A_PtrSize ? "UPtr" : "UInt", pBitmap, "uint*", Width)
   return Width
}
Gdip_GetImageHeight(pBitmap){
   DllCall("gdiplus\GdipGetImageHeight", A_PtrSize ? "UPtr" : "UInt", pBitmap, "uint*", Height)
   return Height
}
Gdip_DeletePen(pPen){
   return DllCall("gdiplus\GdipDeletePen", A_PtrSize ? "UPtr" : "UInt", pPen)
}
Gdip_DeleteBrush(pBrush){
   return DllCall("gdiplus\GdipDeleteBrush", A_PtrSize ? "UPtr" : "UInt", pBrush)
}
Gdip_DisposeImage(pBitmap){
   return DllCall("gdiplus\GdipDisposeImage", A_PtrSize ? "UPtr" : "UInt", pBitmap)
}
Gdip_DeleteGraphics(pGraphics){
   return DllCall("gdiplus\GdipDeleteGraphics", A_PtrSize ? "UPtr" : "UInt", pGraphics)
}
Gdip_DisposeImageAttributes(ImageAttr){
    return DllCall("gdiplus\GdipDisposeImageAttributes", A_PtrSize ? "UPtr" : "UInt", ImageAttr)
}
Gdip_DeleteFont(hFont){
   return DllCall("gdiplus\GdipDeleteFont", A_PtrSize ? "UPtr" : "UInt", hFont)
}
Gdip_DeleteStringFormat(hFormat){
   return DllCall("gdiplus\GdipDeleteStringFormat", A_PtrSize ? "UPtr" : "UInt", hFormat)
}
Gdip_DeleteFontFamily(hFamily){
   return DllCall("gdiplus\GdipDeleteFontFamily", A_PtrSize ? "UPtr" : "UInt", hFamily)
}
CreateCompatibleDC(hdc=0){
   return DllCall("CreateCompatibleDC", A_PtrSize ? "UPtr" : "UInt", hdc)
}
SelectObject(hdc, hgdiobj){
    Ptr := A_PtrSize ? "UPtr" : "UInt"
    return DllCall("SelectObject", Ptr, hdc, Ptr, hgdiobj)
}
DeleteObject(hObject){
   return DllCall("DeleteObject", A_PtrSize ? "UPtr" : "UInt", hObject)
}
GetDC(hwnd=0){
    return DllCall("GetDC", A_PtrSize ? "UPtr" : "UInt", hwnd)
}
GetDCEx(hwnd, flags=0, hrgnClip=0){
    Ptr := A_PtrSize ? "UPtr" : "UInt"
    return DllCall("GetDCEx", Ptr, hwnd, Ptr, hrgnClip, "int", flags)
}
ReleaseDC(hdc, hwnd=0){
    Ptr := A_PtrSize ? "UPtr" : "UInt"
    return DllCall("ReleaseDC", Ptr, hwnd, Ptr, hdc)
}
DeleteDC(hdc){
   return DllCall("DeleteDC", A_PtrSize ? "UPtr" : "UInt", hdc)
}
Gdip_SetClipRegion(pGraphics, Region, CombineMode=0){
    Ptr := A_PtrSize ? "UPtr" : "UInt"
    return DllCall("gdiplus\GdipSetClipRegion", Ptr, pGraphics, Ptr, Region, "int", CombineMode)
}
CreateDIBSection(w, h, hdc="", bpp=32, ByRef ppvBits=0){
    Ptr := A_PtrSize ? "UPtr" : "UInt"
    hdc2 := hdc ? hdc : GetDC()
    VarSetCapacity(bi, 40, 0)
    NumPut(w, bi, 4, "uint"), NumPut(h, bi, 8, "uint"), NumPut(40, bi, 0, "uint"), NumPut(1, bi, 12, "ushort"), NumPut(0, bi, 16, "uInt"), NumPut(bpp, bi, 14, "ushort")
    hbm := DllCall("CreateDIBSection", Ptr, hdc2, Ptr, &bi, "uint", 0, A_PtrSize ? "UPtr*" : "uint*", ppvBits, Ptr, 0, "uint", 0, Ptr)
    if !hdc
        ReleaseDC(hdc2)
    return hbm
}
Gdip_GraphicsFromImage(pBitmap){
    DllCall("gdiplus\GdipGetImageGraphicsContext", A_PtrSize ? "UPtr" : "UInt", pBitmap, A_PtrSize ? "UPtr*" : "UInt*", pGraphics)
    return pGraphics
}
Gdip_GraphicsFromHDC(hdc){
    DllCall("gdiplus\GdipCreateFromHDC", A_PtrSize ? "UPtr" : "UInt", hdc, A_PtrSize ? "UPtr*" : "UInt*", pGraphics)
    return pGraphics
}
Gdip_GetDC(pGraphics){
    DllCall("gdiplus\GdipGetDC", A_PtrSize ? "UPtr" : "UInt", pGraphics, A_PtrSize ? "UPtr*" : "UInt*", hdc)
    return hdc
}

Gdip_Startup(){
    Ptr := A_PtrSize ? "UPtr" : "UInt"
    if !DllCall("GetModuleHandle", "str", "gdiplus", Ptr)
        DllCall("LoadLibrary", "str", "gdiplus")
    VarSetCapacity(si, A_PtrSize = 8 ? 24 : 16, 0), si := Chr(1)
    DllCall("gdiplus\GdiplusStartup", A_PtrSize ? "UPtr*" : "uint*", pToken, Ptr, &si, Ptr, 0)
    return pToken
}

Gdip_TextToGraphics(pGraphics, Text, Options, Font="Arial", Width="", Height="", Measure=0){
    IWidth := Width, IHeight:= Height
    RegExMatch(Options, "i)X([\-\d\.]+)(p*)", xpos)
    RegExMatch(Options, "i)Y([\-\d\.]+)(p*)", ypos)
    RegExMatch(Options, "i)W([\-\d\.]+)(p*)", Width)
    RegExMatch(Options, "i)H([\-\d\.]+)(p*)", Height)
    RegExMatch(Options, "i)C(?!(entre|enter))([a-f\d]+)", Colour)
    RegExMatch(Options, "i)Top|Up|Bottom|Down|vCentre|vCenter", vPos)
    RegExMatch(Options, "i)NoWrap", NoWrap)
    RegExMatch(Options, "i)R(\d)", Rendering)
    RegExMatch(Options, "i)S(\d+)(p*)", Size)
    if !Gdip_DeleteBrush(Gdip_CloneBrush(Colour2))
        PassBrush := 1, pBrush := Colour2
    if !(IWidth && IHeight) && (xpos2 || ypos2 || Width2 || Height2 || Size2)
        return -1
    Style := 0, Styles := "Regular|Bold|Italic|BoldItalic|Underline|Strikeout"
    Loop, Parse, Styles, |
    {
        if RegExMatch(Options, "\b" A_loopField)
        Style |= (A_LoopField != "StrikeOut") ? (A_Index-1) : 8
    }
    Align := 0, Alignments := "Near|Left|Centre|Center|Far|Right"
    Loop, Parse, Alignments, |
    {
        if RegExMatch(Options, "\b" A_loopField)
            Align |= A_Index//2.1      ; 0|0|1|1|2|2
    }
    xpos := (xpos1 != "") ? xpos2 ? IWidth*(xpos1/100) : xpos1 : 0
    ypos := (ypos1 != "") ? ypos2 ? IHeight*(ypos1/100) : ypos1 : 0
    Width := Width1 ? Width2 ? IWidth*(Width1/100) : Width1 : IWidth
    Height := Height1 ? Height2 ? IHeight*(Height1/100) : Height1 : IHeight
    if !PassBrush
        Colour := "0x" (Colour2 ? Colour2 : "ff000000")
    Rendering := ((Rendering1 >= 0) && (Rendering1 <= 5)) ? Rendering1 : 4
    Size := (Size1 > 0) ? Size2 ? IHeight*(Size1/100) : Size1 : 12
    hFamily := Gdip_FontFamilyCreate(Font)
    hFont := Gdip_FontCreate(hFamily, Size, Style)
    FormatStyle := NoWrap ? 0x4000 | 0x1000 : 0x4000
    hFormat := Gdip_StringFormatCreate(FormatStyle)
    pBrush := PassBrush ? pBrush : Gdip_BrushCreateSolid(Colour)
    if !(hFamily && hFont && hFormat && pBrush && pGraphics)
        return !pGraphics ? -2 : !hFamily ? -3 : !hFont ? -4 : !hFormat ? -5 : !pBrush ? -6 : 0
    CreateRectF(RC, xpos, ypos, Width, Height)
    Gdip_SetStringFormatAlign(hFormat, Align)
    Gdip_SetTextRenderingHint(pGraphics, Rendering)
    ReturnRC := Gdip_MeasureString(pGraphics, Text, hFont, hFormat, RC)
    if vPos
    {
        StringSplit, ReturnRC, ReturnRC, |
        if (vPos = "vCentre") || (vPos = "vCenter")
            ypos += (Height-ReturnRC4)//2
        else if (vPos = "Top") || (vPos = "Up")
            ypos := 0
        else if (vPos = "Bottom") || (vPos = "Down")
            ypos := Height-ReturnRC4
        CreateRectF(RC, xpos, ypos, Width, ReturnRC4)
        ReturnRC := Gdip_MeasureString(pGraphics, Text, hFont, hFormat, RC)
    }
    if !Measure
        E := Gdip_DrawString(pGraphics, Text, hFont, hFormat, pBrush, RC)
    if !PassBrush
        Gdip_DeleteBrush(pBrush)
    Gdip_DeleteStringFormat(hFormat)
    Gdip_DeleteFont(hFont)
    Gdip_DeleteFontFamily(hFamily)
    return E ? E : ReturnRC
}
Gdip_DrawString(pGraphics, sString, hFont, hFormat, pBrush, ByRef RectF){
    Ptr := A_PtrSize ? "UPtr" : "UInt"
    if (!A_IsUnicode)
    {
        nSize := DllCall("MultiByteToWideChar", "uint", 0, "uint", 0, Ptr, &sString, "int", -1, Ptr, 0, "int", 0)
        VarSetCapacity(wString, nSize*2)
        DllCall("MultiByteToWideChar", "uint", 0, "uint", 0, Ptr, &sString, "int", -1, Ptr, &wString, "int", nSize)
    }
    return DllCall("gdiplus\GdipDrawString", Ptr, pGraphics, Ptr, A_IsUnicode ? &sString : &wString, "int", -1, Ptr, hFont, Ptr, &RectF, Ptr, hFormat, Ptr, pBrush)
}
Gdip_CreateLineBrush(x1, y1, x2, y2, ARGB1, ARGB2, WrapMode=1){
    Ptr := A_PtrSize ? "UPtr" : "UInt"
    CreatePointF(PointF1, x1, y1), CreatePointF(PointF2, x2, y2)
    DllCall("gdiplus\GdipCreateLineBrush", Ptr, &PointF1, Ptr, &PointF2, "Uint", ARGB1, "Uint", ARGB2, "int", WrapMode, A_PtrSize ? "UPtr*" : "UInt*", LGpBrush)
    return LGpBrush
}
Gdip_CreateLineBrushFromRect(x, y, w, h, ARGB1, ARGB2, LinearGradientMode=1, WrapMode=1){
    CreateRectF(RectF, x, y, w, h)
    DllCall("gdiplus\GdipCreateLineBrushFromRect", A_PtrSize ? "UPtr" : "UInt", &RectF, "int", ARGB1, "int", ARGB2, "int", LinearGradientMode, "int", WrapMode, A_PtrSize ? "UPtr*" : "UInt*", LGpBrush)
    return LGpBrush
}
Gdip_CloneBrush(pBrush){
    DllCall("gdiplus\GdipCloneBrush", A_PtrSize ? "UPtr" : "UInt", pBrush, A_PtrSize ? "UPtr*" : "UInt*", pBrushClone)
    return pBrushClone
}
Gdip_FontFamilyCreate(Font){
    Ptr := A_PtrSize ? "UPtr" : "UInt"
    if (!A_IsUnicode)
    {
        nSize := DllCall("MultiByteToWideChar", "uint", 0, "uint", 0, Ptr, &Font, "int", -1, "uint", 0, "int", 0)
        VarSetCapacity(wFont, nSize*2)
        DllCall("MultiByteToWideChar", "uint", 0, "uint", 0, Ptr, &Font, "int", -1, Ptr, &wFont, "int", nSize)
    }
    DllCall("gdiplus\GdipCreateFontFamilyFromName", Ptr, A_IsUnicode ? &Font : &wFont, "uint", 0, A_PtrSize ? "UPtr*" : "UInt*", hFamily)
    return hFamily
}
Gdip_SetStringFormatAlign(hFormat, Align){
   return DllCall("gdiplus\GdipSetStringFormatAlign", A_PtrSize ? "UPtr" : "UInt", hFormat, "int", Align)
}
Gdip_StringFormatCreate(Format=0, Lang=0){
   DllCall("gdiplus\GdipCreateStringFormat", "int", Format, "int", Lang, A_PtrSize ? "UPtr*" : "UInt*", hFormat)
   return hFormat
}
Gdip_FontCreate(hFamily, Size, Style=0){
   DllCall("gdiplus\GdipCreateFont", A_PtrSize ? "UPtr" : "UInt", hFamily, "float", Size, "int", Style, "int", 0, A_PtrSize ? "UPtr*" : "UInt*", hFont)
   return hFont
}
Gdip_CreatePen(ARGB, w){
   DllCall("gdiplus\GdipCreatePen1", "UInt", ARGB, "float", w, "int", 2, A_PtrSize ? "UPtr*" : "UInt*", pPen)
   return pPen
}
Gdip_CreatePenFromBrush(pBrush, w){
    DllCall("gdiplus\GdipCreatePen2", A_PtrSize ? "UPtr" : "UInt", pBrush, "float", w, "int", 2, A_PtrSize ? "UPtr*" : "UInt*", pPen)
    return pPen
}
Gdip_BrushCreateSolid(ARGB=0xff000000){
    DllCall("gdiplus\GdipCreateSolidFill", "UInt", ARGB, A_PtrSize ? "UPtr*" : "UInt*", pBrush)
    return pBrush
}
Gdip_BrushCreateHatch(ARGBfront, ARGBback, HatchStyle=0){
    DllCall("gdiplus\GdipCreateHatchBrush", "int", HatchStyle, "UInt", ARGBfront, "UInt", ARGBback, A_PtrSize ? "UPtr*" : "UInt*", pBrush)
    return pBrush
}
CreateRectF(ByRef RectF, x, y, w, h){
   VarSetCapacity(RectF, 16)
   NumPut(x, RectF, 0, "float"), NumPut(y, RectF, 4, "float"), NumPut(w, RectF, 8, "float"), NumPut(h, RectF, 12, "float")
}
Gdip_SetTextRenderingHint(pGraphics, RenderingHint){
    return DllCall("gdiplus\GdipSetTextRenderingHint", A_PtrSize ? "UPtr" : "UInt", pGraphics, "int", RenderingHint)
}
Gdip_MeasureString(pGraphics, sString, hFont, hFormat, ByRef RectF){
    Ptr := A_PtrSize ? "UPtr" : "UInt"
    VarSetCapacity(RC, 16)
    if !A_IsUnicode
    {
        nSize := DllCall("MultiByteToWideChar", "uint", 0, "uint", 0, Ptr, &sString, "int", -1, "uint", 0, "int", 0)
        VarSetCapacity(wString, nSize*2)
        DllCall("MultiByteToWideChar", "uint", 0, "uint", 0, Ptr, &sString, "int", -1, Ptr, &wString, "int", nSize)
    }
    DllCall("gdiplus\GdipMeasureString", Ptr, pGraphics, Ptr, A_IsUnicode ? &sString : &wString, "int", -1, Ptr, hFont, Ptr, &RectF, Ptr, hFormat, Ptr, &RC, "uint*", Chars, "uint*", Lines)
    return &RC ? NumGet(RC, 0, "float") "|" NumGet(RC, 4, "float") "|" NumGet(RC, 8, "float") "|" NumGet(RC, 12, "float") "|" Chars "|" Lines : 0
}
CreateRect(ByRef Rect, x, y, w, h){
    VarSetCapacity(Rect, 16)
    NumPut(x, Rect, 0, "uint"), NumPut(y, Rect, 4, "uint"), NumPut(w, Rect, 8, "uint"), NumPut(h, Rect, 12, "uint")
}
CreateSizeF(ByRef SizeF, w, h){
   VarSetCapacity(SizeF, 8)
   NumPut(w, SizeF, 0, "float"), NumPut(h, SizeF, 4, "float")
}
CreatePointF(ByRef PointF, x, y){
   VarSetCapacity(PointF, 8)
   NumPut(x, PointF, 0, "float"), NumPut(y, PointF, 4, "float")
}
Gdip_DrawArc(pGraphics, pPen, x, y, w, h, StartAngle, SweepAngle){
    Ptr := A_PtrSize ? "UPtr" : "UInt"
    return DllCall("gdiplus\GdipDrawArc", Ptr, pGraphics, Ptr, pPen, "float", x, "float", y, "float", w, "float", h, "float", StartAngle, "float", SweepAngle)
}
Gdip_DrawPie(pGraphics, pPen, x, y, w, h, StartAngle, SweepAngle){
    Ptr := A_PtrSize ? "UPtr" : "UInt"
    return DllCall("gdiplus\GdipDrawPie", Ptr, pGraphics, Ptr, pPen, "float", x, "float", y, "float", w, "float", h, "float", StartAngle, "float", SweepAngle)
}
Gdip_DrawLine(pGraphics, pPen, x1, y1, x2, y2){
    Ptr := A_PtrSize ? "UPtr" : "UInt"
    return DllCall("gdiplus\GdipDrawLine", Ptr, pGraphics, Ptr, pPen, "float", x1, "float", y1, "float", x2, "float", y2)
}
Gdip_DrawLines(pGraphics, pPen, Points){
    Ptr := A_PtrSize ? "UPtr" : "UInt"
    StringSplit, Points, Points, |
    VarSetCapacity(PointF, 8*Points0)
    Loop, %Points0%
    {
        StringSplit, Coord, Points%A_Index%, `,
        NumPut(Coord1, PointF, 8*(A_Index-1), "float"), NumPut(Coord2, PointF, (8*(A_Index-1))+4, "float")
    }
    return DllCall("gdiplus\GdipDrawLines", Ptr, pGraphics, Ptr, pPen, Ptr, &PointF, "int", Points0)
}
Gdip_FillRectangle(pGraphics, pBrush, x, y, w, h){
    Ptr := A_PtrSize ? "UPtr" : "UInt"
    return DllCall("gdiplus\GdipFillRectangle", Ptr, pGraphics, Ptr, pBrush, "float", x, "float", y, "float", w, "float", h)
}
Gdip_FillRoundedRectangle(pGraphics, pBrush, x, y, w, h, r){
    Region := Gdip_GetClipRegion(pGraphics)
    Gdip_SetClipRect(pGraphics, x-r, y-r, 2*r, 2*r, 4)
    Gdip_SetClipRect(pGraphics, x+w-r, y-r, 2*r, 2*r, 4)
    Gdip_SetClipRect(pGraphics, x-r, y+h-r, 2*r, 2*r, 4)
    Gdip_SetClipRect(pGraphics, x+w-r, y+h-r, 2*r, 2*r, 4)
    E := Gdip_FillRectangle(pGraphics, pBrush, x, y, w, h)
    Gdip_SetClipRegion(pGraphics, Region, 0)
    Gdip_SetClipRect(pGraphics, x-(2*r), y+r, w+(4*r), h-(2*r), 4)
    Gdip_SetClipRect(pGraphics, x+r, y-(2*r), w-(2*r), h+(4*r), 4)
    Gdip_FillEllipse(pGraphics, pBrush, x, y, 2*r, 2*r)
    Gdip_FillEllipse(pGraphics, pBrush, x+w-(2*r), y, 2*r, 2*r)
    Gdip_FillEllipse(pGraphics, pBrush, x, y+h-(2*r), 2*r, 2*r)
    Gdip_FillEllipse(pGraphics, pBrush, x+w-(2*r), y+h-(2*r), 2*r, 2*r)
    Gdip_SetClipRegion(pGraphics, Region, 0)
    Gdip_DeleteRegion(Region)
    return E
}
Gdip_GetClipRegion(pGraphics){
    Region := Gdip_CreateRegion()
    DllCall("gdiplus\GdipGetClip", A_PtrSize ? "UPtr" : "UInt", pGraphics, "UInt*", Region)
    return Region
}
Gdip_SetClipRect(pGraphics, x, y, w, h, CombineMode=0){
   return DllCall("gdiplus\GdipSetClipRect",  A_PtrSize ? "UPtr" : "UInt", pGraphics, "float", x, "float", y, "float", w, "float", h, "int", CombineMode)
}
Gdip_SetClipPath(pGraphics, Path, CombineMode=0){
    Ptr := A_PtrSize ? "UPtr" : "UInt"
    return DllCall("gdiplus\GdipSetClipPath", Ptr, pGraphics, Ptr, Path, "int", CombineMode)
}
Gdip_ResetClip(pGraphics){
   return DllCall("gdiplus\GdipResetClip", A_PtrSize ? "UPtr" : "UInt", pGraphics)
}
Gdip_FillEllipse(pGraphics, pBrush, x, y, w, h){
    Ptr := A_PtrSize ? "UPtr" : "UInt"
    return DllCall("gdiplus\GdipFillEllipse", Ptr, pGraphics, Ptr, pBrush, "float", x, "float", y, "float", w, "float", h)
}
Gdip_FillRegion(pGraphics, pBrush, Region){
    Ptr := A_PtrSize ? "UPtr" : "UInt"
    return DllCall("gdiplus\GdipFillRegion", Ptr, pGraphics, Ptr, pBrush, Ptr, Region)
}
Gdip_FillPath(pGraphics, pBrush, Path){
    Ptr := A_PtrSize ? "UPtr" : "UInt"
    return DllCall("gdiplus\GdipFillPath", Ptr, pGraphics, Ptr, pBrush, Ptr, Path)
}
Gdip_CreateRegion(){
    DllCall("gdiplus\GdipCreateRegion", "UInt*", Region)
    return Region
}
Gdip_DeleteRegion(Region){
    return DllCall("gdiplus\GdipDeleteRegion", A_PtrSize ? "UPtr" : "UInt", Region)
}
Gdip_CreateBitmap(Width, Height, Format=0x26200A){
    DllCall("gdiplus\GdipCreateBitmapFromScan0", "int", Width, "int", Height, "int", 0, "int", Format, A_PtrSize ? "UPtr" : "UInt", 0, A_PtrSize ? "UPtr*" : "uint*", pBitmap)
    Return pBitmap
}
Gdip_SetSmoothingMode(pGraphics, SmoothingMode){
   return DllCall("gdiplus\GdipSetSmoothingMode", A_PtrSize ? "UPtr" : "UInt", pGraphics, "int", SmoothingMode)
}
Gdip_DrawRectangle(pGraphics, pPen, x, y, w, h){
    Ptr := A_PtrSize ? "UPtr" : "UInt"
    return DllCall("gdiplus\GdipDrawRectangle", Ptr, pGraphics, Ptr, pPen, "float", x, "float", y, "float", w, "float", h)
}
Gdip_DrawRoundedRectangle(pGraphics, pPen, x, y, w, h, r){
    Gdip_SetClipRect(pGraphics, x-r, y-r, 2*r, 2*r, 4)
    Gdip_SetClipRect(pGraphics, x+w-r, y-r, 2*r, 2*r, 4)
    Gdip_SetClipRect(pGraphics, x-r, y+h-r, 2*r, 2*r, 4)
    Gdip_SetClipRect(pGraphics, x+w-r, y+h-r, 2*r, 2*r, 4)
    E := Gdip_DrawRectangle(pGraphics, pPen, x, y, w, h)
    Gdip_ResetClip(pGraphics)
    Gdip_SetClipRect(pGraphics, x-(2*r), y+r, w+(4*r), h-(2*r), 4)
    Gdip_SetClipRect(pGraphics, x+r, y-(2*r), w-(2*r), h+(4*r), 4)
    Gdip_DrawEllipse(pGraphics, pPen, x, y, 2*r, 2*r)
    Gdip_DrawEllipse(pGraphics, pPen, x+w-(2*r), y, 2*r, 2*r)
    Gdip_DrawEllipse(pGraphics, pPen, x, y+h-(2*r), 2*r, 2*r)
    Gdip_DrawEllipse(pGraphics, pPen, x+w-(2*r), y+h-(2*r), 2*r, 2*r)
    Gdip_ResetClip(pGraphics)
    return E
}
Gdip_DrawEllipse(pGraphics, pPen, x, y, w, h){
    Ptr := A_PtrSize ? "UPtr" : "UInt"
    return DllCall("gdiplus\GdipDrawEllipse", Ptr, pGraphics, Ptr, pPen, "float", x, "float", y, "float", w, "float", h)
}
Gdip_CreateHBITMAPFromBitmap(pBitmap, Background=0xffffffff){
    DllCall("gdiplus\GdipCreateHBITMAPFromBitmap", A_PtrSize ? "UPtr" : "UInt", pBitmap, A_PtrSize ? "UPtr*" : "uint*", hbm, "int", Background)
    return hbm
}
SetImage(hwnd, hBitmap){
    SendMessage, 0x172, 0x0, hBitmap,, ahk_id %hwnd%
    E := ErrorLevel
    DeleteObject(E)
    return E
}
Gdip_FillPolygon(pGraphics, pBrush, Points, FillMode=0){
    Ptr := A_PtrSize ? "UPtr" : "UInt"
    StringSplit, Points, Points, |
    VarSetCapacity(PointF, 8*Points0)
    Loop, %Points0%
    {
        StringSplit, Coord, Points%A_Index%, `,
        NumPut(Coord1, PointF, 8*(A_Index-1), "float"), NumPut(Coord2, PointF, (8*(A_Index-1))+4, "float")
    }
    return DllCall("gdiplus\GdipFillPolygon", Ptr, pGraphics, Ptr, pBrush, Ptr, &PointF, "int", Points0, "int", FillMode)
}

UpdateLayeredWindow(hwnd, hdc, x="", y="", w="", h="", Alpha=255)
{
    Ptr := A_PtrSize ? "UPtr" : "UInt"

    if ((x != "") && (y != ""))
        VarSetCapacity(pt, 8), NumPut(x, pt, 0, "UInt"), NumPut(y, pt, 4, "UInt")

    if (w = "") ||(h = "")
        WinGetPos,,, w, h, ahk_id %hwnd%

    return DllCall("UpdateLayeredWindow"
                    , Ptr, hwnd
                    , Ptr, 0
                    , Ptr, ((x = "") && (y = "")) ? 0 : &pt
                    , "int64*", w|h<<32
                    , Ptr, hdc
                    , "int64*", 0
                    , "uint", 0
                    , "UInt*", Alpha<<16|1<<24
                    , "uint", 2)
}

Gdip_GraphicsClear(pGraphics, ARGB=0x00ffffff)
{
    return DllCall("gdiplus\GdipGraphicsClear", A_PtrSize ? "UPtr" : "UInt", pGraphics, "int", ARGB)
}

Return to “Ask for Help (v1)”

Who is online

Users browsing this forum: Google [Bot], wilkster and 336 guests