[class] PopUpWindow (Layered Windows )

Post your working scripts, libraries and tools for AHK v1.1 and older
User avatar
Hellbent
Posts: 2109
Joined: 23 Sep 2017, 13:34

[class] PopUpWindow (Layered Windows )

Post by Hellbent » 23 Sep 2021, 14:14

I hadn't planed on creating a thread for this because I already have a another class for handling working with layered windows here on the forum, but I was in a meeting with @Joe Glines yesterday and he mentioned needing a simple way to get images on the screen, and I told him about my layered window prototyping class. Anyways, Joe thought it would be a good idea to record it and post it to youtube, so I thought I would make this thread, and if anyone has questions they can ask here rather than in the comment section of some youtube video.

Before you go diving further, let me tell you a little about the class and why you want it (particularly if you don't know what the heck a layered window is).

A layered window is basically a window that only shows things that you draw onto it. So if you draw a .png that has transparency it will keep that transparency when you show it. Besides only showing things that you draw to it, it also performs vastly better than normal guis for any kind of animations, and is flicker free! So that's what a layered window is.
The class is just all the code to set up a new instance of a layered window and has a few basic functions that you can use to keep things super simple.

How to use this class:



In addition to that, you can find tons of examples of using the class here on the forum by searching for "PopUpWindow"

A simple example you can try to make for yourself is a simple hotkey script that creates little text bubbles on your screen.
It is as simple as drawing a rounded rectangle and then drawing a text string on top of it. You can get really fancy with it too by adding borders and by using color gradients ( all things you can find in the gdip lib ).

Here is the class:

Code: Select all

;************************************************************************************************************************************************************************************************
;************************************************************************************************************************************************************************************************
;************************************************************************************************************************************************************************************************
;************************************************************************************************************************************************************************************************
;************************************************************************************************************************************************************************************************
class PopUpWindow	{
	;Class By: Hellbent
	;Apr 2021
	static Index := 0 , Windows := [] , Handles := [] , HelpHandles := [] , HelperEditHwnd
	__New( obj := "" ){
		This._SetDefaults()
		if( isObject( obj ) )
			This.SetWindowProperties( obj )
		This._SetupWindowGraphics()
	}
	_SetDefaults(){
		PopUpWindow.Index++
		This.WindowName := "HBLayeredWindow" PopUpWindow.Index
		This.WindowSmoothing := 2
		This.WindowOptions := " -DPIScale +AlwaysOnTop "
		This.X := 10
		This.Y := 10
		This.W := 10
		This.H := 10
	}
	PaintBackground( color := "0xFF000000" ){
		Brush := Gdip_BrushCreateSolid( color ) 
		Gdip_FillRectangle( This.G , Brush , -1 , -1 , This.W + 2 , This.H + 2 ) 
		Gdip_DeleteBrush( Brush )
	}
	_SetupWindowGraphics(){
		This.Hwnd := This._CreateGUI()
		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.WindowSmoothing )
		PopUpWindow.Handles[ This.Hwnd ] := PopUpWindow.Index
		PopUpWindow.Windows[ PopUpWindow.Index ] := This
	}
	SetWindowProperties( obj , updateG := 0 ){
		local k , v 
		for k , v in obj
			if( k != "hwnd" )
				This[k] := v
			
			
		if(updateG){	
			SelectObject( This.hdc , This.obm )
			DeleteObject( This.hbm )
			DeleteDC( This.hdc )
			
			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.WindowSmoothing )	
		}
		( This.X = "center" ) ? ( This.X := ( A_ScreenWidth - This.W ) / 2 )
		( This.Y = "center" ) ? ( This.Y := ( A_ScreenHeight - This.H ) / 2 )
	}
	ShowWindow( Title := "" ){
		Gui , % This.WindowName ":Show", % "x" This.X " y" This.Y " w" This.W " h" This.H " NA", % Title
	}
	HideWindow(){
		Gui , % This.WindowName ":Hide",
	}
	UpdateWindow(){
		UpdateLayeredWindow( This.hwnd , This.hdc , This.X , This.Y , This.W , This.H )
	}
	ClearWindow(){
		Gdip_GraphicsClear( This.G )
	}
	DrawBitmap( pBitmap , obj , dispose := 1 ){
		Gdip_DrawImage( This.G , pBitmap , obj.X , obj.Y , obj.W , obj.H )
		if( dispose )
			Gdip_DisposeImage( pBitmap )
	}
	DeleteWindow(){
		Gui, % This.WindowName ":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 ] := ""
	}
	_CreateGUI(){
		local hwnd
		Gui , % This.WindowName ":New" , % " +E0x80000 hwndhwnd -Caption  " This.WindowOptions
		return hwnd
	}
	Helper(){
		local List := ["New Window","SetWindowProperties","ShowWindow","HideWindow","UpdateWindow","ClearWindow","DrawBitmap","PaintBackground","DeleteWindow"]
		local hwnd, bd
		
		
		Gui, HBLWHelperGui:New, +AlwaysOnTop 
		Gui, HBLWHelperGui:Color, 62666a, 24282c
		Gui, HBLWHelperGui:Font, cWhite s10 , Segoe UI
		Gui, HBLWHelperGui:Margin, 5 , 5
		
		Gui, HBLWHelperGui:Add, Edit, xm ym w200 r1 Center hwndHwnd, Gui1
		PopUpWindow.HelperEditHwnd := Hwnd
		Gui, HBLWHelperGui:Margin, 5 , 1
		Loop, % List.Length()	{
		
			Gui, HBLWHelperGui:Add, Button, xm wp h23 -Theme hwndhwnd, % List[ A_Index ]
			PopUpWindow.HelpHandles[hwnd] := List[ A_Index ]
			bd := PopUpWindow._ClipIt.Bind( PopUpWindow )
			GuiControl , HBLWHelperGui: +G , % Hwnd , % bd
		}
		
		Gui, HBLWHelperGui:Show, 
		
	}
	_ClipIt(){
		local List := ["New Window","SetWindowProperties","ShowWindow","HideWindow","UpdateWindow","ClearWindow","DrawBitmap","PaintBackground","DeleteWindow"]
		local Output , FQ := 400
		GuiControlGet, Output , HBLWHelperGui: , % PopUpWindow.HelperEditHwnd
		Switch A_GuiControl
		{
			case List[1]:
				Clipboard := Output " := New PopUpWindow( { WindowName: ""1"" , WindowOptions: "" -DPIScale +AlwaysOnTop "" , WindowSmoothing: 2 , X: ""Center"" , Y: ""Center"" , W: 100 , H: 100 } )"
				loop 2
					SoundBeep, FQ
				return
			case List[2]:
				Clipboard := Output ".SetWindowProperties( { X: """" , Y: """" , W: """" , H: """" } )"
				loop 2
					SoundBeep, FQ
				return
			case List[3]:
				Clipboard := Output ".ShowWindow( MyWindowTitle := """" )"
				loop 2
					SoundBeep, FQ
				return
			case List[4]:
				Clipboard := Output ".HideWindow()"
				loop 2
					SoundBeep, FQ
				return
			case List[5]:
				Clipboard := Output ".UpdateWindow()"
				loop 2
					SoundBeep, FQ
				return
			case List[6]:
				Clipboard := Output ".ClearWindow()"
				loop 2
					SoundBeep, FQ
				return
			case List[7]:
				Clipboard := Output ".DrawBitmap( pBitmap := """" , { X: """" , Y: """" , W: """" , H: """" } , dispose := 1 )"
				loop 2
					SoundBeep, FQ
				return
			case List[8]:
				Clipboard := Output ".PaintBackground( color := ""0xFF000000"" )"
				loop 2
					SoundBeep, FQ
				return
			case List[9]:
				Clipboard := Output ".DeleteWindow()"
				loop 2
					SoundBeep, FQ
				return
			Default:
				ToolTip, Looks like a new case needs to be added
				return
			
		}
	}
}
Questions?

User avatar
Hellbent
Posts: 2109
Joined: 23 Sep 2017, 13:34

Re: [class] PopUpWindow (Layered Windows )

Post by Hellbent » 23 Sep 2021, 14:17

What you see:
Temp (1).gif
Temp (1).gif (267.12 KiB) Viewed 4930 times
Reality:
Temp (1).gif
Temp (1).gif (273.33 KiB) Viewed 4930 times

AHKStudent
Posts: 1472
Joined: 05 May 2018, 12:23

Re: [class] PopUpWindow (Layered Windows )

Post by AHKStudent » 23 Sep 2021, 20:02

learned a lot from that video, I always thought those types of GUI require the use of winset, transcolor etc, when I tried it a long time ago it always created issues with these jagged edges, thanks for taking the time to explain it in detail

User avatar
Hellbent
Posts: 2109
Joined: 23 Sep 2017, 13:34

Re: [class] PopUpWindow (Layered Windows )

Post by Hellbent » 24 Sep 2021, 03:55

AHKStudent wrote:
23 Sep 2021, 20:02
learned a lot from that video, I always thought those types of GUI require the use of winset, transcolor etc, when I tried it a long time ago it always created issues with these jagged edges, thanks for taking the time to explain it in detail
You're welcome.
I was actually going to message you about going with this method for at least parts of your project. I imagine by now you are having issues with displaying the different layers for your animations unless you found some other creative way of doing it. Either way I could see that performance was going to cause some issues so I was going to message you a few days ago but I knew it would take me a while to cover the basics and I was feeling too lazy to commit to the time so I put it off for a while lol. I guess the good thing is that you now should have a basic understanding of how layered windows work and how to use the class to make things easy while working with them.


Here are a few tips that may be helpful with your project.

1. The frame rate you use for your animations is very important. This is because the frame rate you will be drawing your graphics is also the rate things change. Your instinct might be to go with as high of a frame rate as you possibly can, but chances are that you will get choppy graphics whenever you have your high and low loads. Your best bet is to find the times where your cpu is put under the most strain and get a sample of the lowest fps values and use a timing that is around that value (a few exceptions could exist). That will give you stable frame rates as your program runs through its animation sequences. The other choice is to use change in time for your calculations rather than using a simple increment. That would give you more consistent animations even under load and at higher frame rates. Unless you already know how to do that, I would just pretend I didn't mention it. I only bring it up because IT IS a way you could do things , and even get better results, but doing that on your first (one of your first) project is just asking for a bad time.

2. If you plan on sharing your code, I recommend setting up a fps test in your code and having it run on a number of computers to see how it does.

3. If you decide to use a layered window and plan on making your script windows 8+ only, you can use a normal gui as your main window / background and then add as many child layered windows as it makes sense to use for your different animation layers. What you are looking to do is not draw anything more often than you have to. So perhaps the background gets a layer and is only drawn once. I know that you have at least two animation layers, so they both get their own layer each. Then perhaps a overlay layer with the different values you are displaying. etc etc.

AHKStudent
Posts: 1472
Joined: 05 May 2018, 12:23

Re: [class] PopUpWindow (Layered Windows )

Post by AHKStudent » 24 Sep 2021, 17:15

Hellbent wrote:
24 Sep 2021, 03:55
AHKStudent wrote:
23 Sep 2021, 20:02
learned a lot from that video, I always thought those types of GUI require the use of winset, transcolor etc, when I tried it a long time ago it always created issues with these jagged edges, thanks for taking the time to explain it in detail
You're welcome.
I was actually going to message you about going with this method for at least parts of your project. I imagine by now you are having issues with displaying the different layers for your animations unless you found some other creative way of doing it. Either way I could see that performance was going to cause some issues so I was going to message you a few days ago but I knew it would take me a while to cover the basics and I was feeling too lazy to commit to the time so I put it off for a while lol. I guess the good thing is that you now should have a basic understanding of how layered windows work and how to use the class to make things easy while working with them.


Here are a few tips that may be helpful with your project.

1. The frame rate you use for your animations is very important. This is because the frame rate you will be drawing your graphics is also the rate things change. Your instinct might be to go with as high of a frame rate as you possibly can, but chances are that you will get choppy graphics whenever you have your high and low loads. Your best bet is to find the times where your cpu is put under the most strain and get a sample of the lowest fps values and use a timing that is around that value (a few exceptions could exist). That will give you stable frame rates as your program runs through its animation sequences. The other choice is to use change in time for your calculations rather than using a simple increment. That would give you more consistent animations even under load and at higher frame rates. Unless you already know how to do that, I would just pretend I didn't mention it. I only bring it up because IT IS a way you could do things , and even get better results, but doing that on your first (one of your first) project is just asking for a bad time.

2. If you plan on sharing your code, I recommend setting up a fps test in your code and having it run on a number of computers to see how it does.

3. If you decide to use a layered window and plan on making your script windows 8+ only, you can use a normal gui as your main window / background and then add as many child layered windows as it makes sense to use for your different animation layers. What you are looking to do is not draw anything more often than you have to. So perhaps the background gets a layer and is only drawn once. I know that you have at least two animation layers, so they both get their own layer each. Then perhaps a overlay layer with the different values you are displaying. etc etc.
The layered window video with you and joe was timed just right. I added a whole other gif animation and it becomes impossible to work within one gui and adding another gui transparent that is not a layered style window is even a bigger problem.

Gifs using gdip is amazing but even that, I needed to learn how to clean the gif up itself so im using ezgif online to edit the gif, remove frames mostly at the start or end that cause issues etc.

Thanks!

User avatar
Hellbent
Posts: 2109
Joined: 23 Sep 2017, 13:34

Re: [class] PopUpWindow (Layered Windows )

Post by Hellbent » 24 Sep 2021, 17:23

AHKStudent wrote:
24 Sep 2021, 17:15

Gifs using gdip is amazing but even that, I needed to learn how to clean the gif up itself so im using ezgif online to edit the gif, remove frames mostly at the start or end that cause issues etc.

Thanks!
If your gif is what I think it is, then you shouldn't need it to get what you want.
PM me your gif ( not the actual file )

User avatar
Joe Glines
Posts: 770
Joined: 30 Sep 2013, 20:49
Location: Dallas
Contact:

Re: [class] PopUpWindow (Layered Windows )

Post by Joe Glines » 25 Sep 2021, 07:52

Great post and call with you Hellbent! It's awesome to have this stuff open to everyone! :)
Sign-up for the 🅰️HK Newsletter

ImageImageImageImage:clap:
AHK Tutorials:Web Scraping | | Webservice APIs | AHK and Excel | Chrome | RegEx | Functions
Training: AHK Webinars Courses on AutoHotkey :ugeek:
YouTube

:thumbup: Quick Access Popup, the powerful Windows folders, apps and documents launcher!

User avatar
iilabs
Posts: 296
Joined: 07 Jun 2020, 16:57

Re: [class] PopUpWindow (Layered Windows )

Post by iilabs » 26 Sep 2021, 10:20

Great work Hellbent! Watched the video and very informative Glines. Thank you!

User avatar
Hellbent
Posts: 2109
Joined: 23 Sep 2017, 13:34

Re: [class] PopUpWindow (Layered Windows )

Post by Hellbent » 26 Sep 2021, 12:07

iilabs wrote:
26 Sep 2021, 10:20
Great work Hellbent! Watched the video and very informative Glines. Thank you!
Thanks man!

Hope you find it helpful.

User avatar
SirSocks
Posts: 360
Joined: 26 Oct 2018, 08:14

Re: [class] PopUpWindow (Layered Windows )

Post by SirSocks » 21 Oct 2021, 07:10

Very educational video! Thanks a lot for sharing your knowledge.

vanheartnet098
Posts: 61
Joined: 01 Sep 2020, 09:49

Re: [class] PopUpWindow (Layered Windows )

Post by vanheartnet098 » 08 Sep 2022, 01:36

@Hellbent
Hi, thanks for this class i can now make smooth rounded guis. been wondering, How can i add default control in this gui such as text, button, picture and specially listview and listbox that i need in my project. Ive been using your custom button controls but the problem is i dont know how can add those controls above the layered window.

User avatar
Hellbent
Posts: 2109
Joined: 23 Sep 2017, 13:34

Re: [class] PopUpWindow (Layered Windows )

Post by Hellbent » 08 Sep 2022, 19:38

vanheartnet098 wrote:
08 Sep 2022, 01:36
@Hellbent
Hi, thanks for this class i can now make smooth rounded guis. been wondering, How can i add default control in this gui such as text, button, picture and specially listview and listbox that i need in my project. Ive been using your custom button controls but the problem is i dont know how can add those controls above the layered window.
You have three options available to you to add default controls.

1. Use a "composite" window as a child of the popup window and add your controls to it.

Here is an example. You can find more context here:
viewtopic.php?p=463560#p463560

This creates a inner window for the layered window. The main takeaway is setting your child with these two options: +E0x02000000 +E0x00080000

Code: Select all

	_CreateInnerPanel(){
		This.InnerPanel := {}
		This.InnerPanel.X := This.Margin.X 
		This.InnerPanel.Y := This.Margin.Y
		This.InnerPanel.W := This.Clip.W
		This.InnerPanel.H := This.Clip.H
		This.InnerPanel.Options := " -Caption -DPIScale +Parent" This.CenterPanel.Hwnd " +E0x02000000 +E0x00080000 "
		Gui, New, % This.InnerPanel.Options " hwndhwnd"
		This.InnerPanel.Hwnd := hwnd
		Gui, Color, % This.Color
		Gui, Show, % "x" This.InnerPanel.X " y" This.InnerPanel.Y " w" This.InnerPanel.W " h" This.InnerPanel.H " NA"
	}



2. Use a Owned window that sits on top of the popup window.

3. Create your own custom controls that can be drawn on the layered window ( beginner to very advanced )

Here are two VERY simple examples of adding very simple click triggers.


Any version of windows:

Code: Select all

;****************************************************************************************************************************************************************************
#Include <My Altered GDIP lib> ;<<<<<<<<<<<<<<<<<<---------------------------     gdip.ahk
#Include <PopUpWindow_V2> ;Version 2
;****************************************************************************************************************************************************************************
#SingleInstance, Force
SetBatchLines, -1
Gdip_Startup()

Gui1 := New PopUpWindow( { AutoShow: 1 , X: 800 , Y: 130 , W: 400 , H: 200 , Options: " -DPIScale +AlwaysOnTop " } )
Gui1.PaintBackground( { Color: "0x66000000" , X: 2 , Y: 2 , W: Gui1.W - 4 , H: Gui1.H - 4 , Round: 10 } ) 

Gui1.Controls := {}

Gui1.Controls.Button1 := { X: 10 , Y: 10 , W: 100 , H: 30 , Label: "MoveWindow" , Value: "Move" , Color: "0xFFFF0000" }
Gui1.Controls.Button2 := { X: 10 , Y: 50 , W: 100 , H: 30 , Label: "ShowMessage" , Value: "Show Message" , Color: "0xFF00ff00" }
Gui1.Controls.Button3 := { X: 10 , Y: 90 , W: 100 , H: 30 , Label: "MakeNoise" , Value: "Play Sounds" , Color: "0xFFFFff00" }

for k , v in Gui1.Controls	{
	cc := Gui1.Controls[ k ]
	FillRectangle( Gui1.G , cc.x , cc.y , cc.w , cc.h , cc.color )
	DrawText( Gui1.G , cc.x , cc.y , cc.Value ,  "0xFF000000" , cc.W , cc.H , options := " Center vCenter Bold s12 " , type := "comic Sans MS" )
}

Gui1.UpdateWindow()


OnMessage( 0x201 , Func( "OnClick").Bind( Gui1 ) )

return
GuiClose:
GuiContextMenu:
*ESC::ExitApp

RALT::PopUpWindow.Helper()

MoveWindow:
	PostMessage, 0xA1 , 2
	While( GetKeyState( "LButton" ) )
		sleep, 30
	WinGetPos, x, y,,, % "ahk_id " Gui1.Hwnd
	Gui1.UpdateSettings( { X: x , Y: y } )
	return

MakeNoise:
	fq := 400
	Loop, 10
		SoundBeep, % fq += 100
	return

ShowMessage:
	Gui, % Gui1.Hwnd ": +OwnDialogs"
	MsgBox, Blah Blah Blah
	return


DrawText( G , x , y , text ,  color , width , height , options := " Center vCenter Bold s12 " , type := "comic Sans MS" ){
	Brush := Gdip_BrushCreateSolid( color ) , Gdip_TextToGraphics( G , text , options " c" brush " x" x " y" y  , type , width , height ) , Gdip_DeleteBrush( Brush )
}

FillRectangle( G , x , y , w , h , color := "0xFFFF0000" ){
	Brush := Gdip_BrushCreateSolid( color ) , Gdip_FillRectangle( G , Brush , x , y , w , h ) , Gdip_DeleteBrush( Brush )
}

OnClick( gui1 ){
	
	CoordMode, Mouse, Client 
	MouseGetPos, x , y 
	for k, v in Gui1.Controls	{
		cc := Gui1.Controls[ k ]
		if( x >= cc.X && x <= ( cc.X + cc.W ) && y >= cc.Y && y <= ( cc.Y + cc.H ) ){
			goSub, % cc.Label
			return
		}
	
	}
	
}


Windows 8+

Code: Select all

;****************************************************************************************************************************************************************************
#Include <My Altered GDIP lib> ;<<<<<<<<<<<<<<<<<<---------------------------     gdip.ahk
#Include <PopUpWindow_V2> ;Version 2
;****************************************************************************************************************************************************************************
#SingleInstance, Force
SetBatchLines, -1
Gdip_Startup()

Gui1 := New PopUpWindow( { AutoShow: 1 , X: 800 , Y: 130 , W: 400 , H: 200 , Options: " -DPIScale +AlwaysOnTop " } )
Gui1.PaintBackground( { Color: "0x66000000" , X: 2 , Y: 2 , W: Gui1.W - 4 , H: Gui1.H - 4 , Round: 10 } ) 

Gui1.PaintBackground( cc := { Color: "0xFFffffff" , X: 12 , Y: 12 , W: 100 , H: 30 , Round: 10 } ) 
DrawText( Gui1.G , cc.x , cc.y , "Move" ,  "0xFF000000" , cc.W , cc.H , options := " Center vCenter Bold s12 " , type := "comic Sans MS" )
Gui, % Gui1.Hwnd ":Add" , Text , % "x" cc.X " y" cc.Y " w" cc.W " h" cc.H " gMoveWindow" 

Gui1.PaintBackground( cc := { Color: "0xFF00ff00" , X: 12 , Y: 52 , W: 100 , H: 30 , Round: 10 } ) 
DrawText( Gui1.G , cc.x , cc.y , "Show Message" ,  "0xFF000000" , cc.W , cc.H , options := " Center vCenter Bold s12 " , type := "comic Sans MS" )
Gui, % Gui1.Hwnd ":Add" , Text , % "x" cc.X " y" cc.Y " w" cc.W " h" cc.H " gShowMessage" 

Gui1.PaintBackground( cc := { Color: "0xFFff0000" , X: 12 , Y: 92 , W: 100 , H: 30 , Round: 10 } ) 
DrawText( Gui1.G , cc.x , cc.y , "Play Sounds" ,  "0xFF000000" , cc.W , cc.H , options := " Center vCenter Bold s12 " , type := "comic Sans MS" )
Gui, % Gui1.Hwnd ":Add" , Text , % "x" cc.X " y" cc.Y " w" cc.W " h" cc.H " gMakeNoise" 

Gui1.UpdateWindow()


return
GuiClose:
GuiContextMenu:
*ESC::ExitApp

RALT::PopUpWindow.Helper()

MoveWindow:
	PostMessage, 0xA1 , 2
	While( GetKeyState( "LButton" ) )
		sleep, 30
	WinGetPos, x, y,,, % "ahk_id " Gui1.Hwnd
	Gui1.UpdateSettings( { X: x , Y: y } )
	return

MakeNoise:
	fq := 400
	Loop, 10
		SoundBeep, % fq += 100
	return

ShowMessage:
	Gui, % Gui1.Hwnd ": +OwnDialogs"
	MsgBox, Blah Blah Blah
	return


DrawText( G , x , y , text ,  color , width , height , options := " Center vCenter Bold s12 " , type := "comic Sans MS" ){
	Brush := Gdip_BrushCreateSolid( color ) , Gdip_TextToGraphics( G , text , options " c" brush " x" x " y" y  , type , width , height ) , Gdip_DeleteBrush( Brush )
}
temp.gif
temp.gif (267.51 KiB) Viewed 3393 times

Those are as basic as it gets. From there it can get very complicated, here is an example of a prototype for a DDL control.
viewtopic.php?f=6&t=3851&start=320#p443722

Image

User avatar
Hellbent
Posts: 2109
Joined: 23 Sep 2017, 13:34

Re: [class] PopUpWindow (Layered Windows )

Post by Hellbent » 08 Sep 2022, 19:57

post #2

@vanheartnet098
Adding a picture can be as simple as creating a pBitmap of your image and then using the "DrawBitmap" class method

Code: Select all

;****************************************************************************************************************************************************************************
#Include <My Altered GDIP lib> ;<<<<<<<<<<<<<<<<<<---------------------------     gdip.ahk
#Include <PopUpWindow_V2> ;Version 2
;****************************************************************************************************************************************************************************
#SingleInstance, Force
SetBatchLines, -1
Gdip_Startup()

Gui1 := New PopUpWindow( { AutoShow: 1 , X: "center" , Y: "center" , W: 1243 , H: 234 , Options: " -DPIScale +AlwaysOnTop " } )
Gui1.PaintBackground( { Color: "0x66000000" , X: 2 , Y: 2 , W: Gui1.W - 4 , H: Gui1.H - 4 , Round: 10 } ) 
Gui1.DrawBitmap( HB_BITMAP_MAKER( scale := 1 ) , { X: 0 , Y: 0 , W: Gui1.W * scale , H: Gui1.H * scale } , dispose := 1 , AutoUpdate := 1 )

return
GuiClose:
GuiContextMenu:
*ESC::ExitApp

RALT::PopUpWindow.Helper()

HB_BITMAP_MAKER( ScaleFactor := 1 ){
	;Bitmap Created Using: HB Bitmap Maker
	pBitmap := Gdip_CreateBitmap( 1243 * ScaleFactor , 234 * ScaleFactor ) , G := Gdip_GraphicsFromImage( pBitmap ) , Gdip_SetSmoothingMode( G , 2 )
	picBitmap := Gdip_CreateBitmapFromFile( "C:\Users\CivRe\OneDrive\Desktop\AHK Tools\Color Picker Mini\Screen Shots\20220908204338.png" ) , Gdip_DrawImage( G , picBitmap , 20 * ScaleFactor , 60 * ScaleFactor , 1153 * ScaleFactor , 144 * ScaleFactor , 0 , 0 , 1153 , 144 ) , Gdip_DisposeImage( picBitmap )
	Gdip_DeleteGraphics( G )
	return pBitmap
}
temp.gif
temp.gif (175.39 KiB) Viewed 3386 times

vanheartnet098
Posts: 61
Joined: 01 Sep 2020, 09:49

Re: [class] PopUpWindow (Layered Windows )

Post by vanheartnet098 » 09 Sep 2022, 08:28

@Hellbent
Thank you for these reference making it much more easy to understand the layered window, looking forward for your more amazing Tutorials.

greatwhitepine
Posts: 8
Joined: 16 Feb 2023, 01:24

Re: [class] PopUpWindow (Layered Windows )

Post by greatwhitepine » 16 Feb 2023, 12:32

Is there a 2.02 version of this?

User avatar
Hellbent
Posts: 2109
Joined: 23 Sep 2017, 13:34

Re: [class] PopUpWindow (Layered Windows )

Post by Hellbent » 17 Feb 2023, 13:53

greatwhitepine wrote:
16 Feb 2023, 12:32
Is there a 2.02 version of this?


Yes, here it is.

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 ){
		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 ]
		
	}
}

greatwhitepine
Posts: 8
Joined: 16 Feb 2023, 01:24

Re: [class] PopUpWindow (Layered Windows )

Post by greatwhitepine » 17 Feb 2023, 17:51

Hellbent wrote:
17 Feb 2023, 13:53
Yes, here it is.
2.0.2 doesn't use the same syntax used in your file. I've got a modified version that works in 2.0.2 almost done. I'm good.

User avatar
Hellbent
Posts: 2109
Joined: 23 Sep 2017, 13:34

Re: [class] PopUpWindow (Layered Windows )

Post by Hellbent » 18 Feb 2023, 00:09

greatwhitepine wrote:
17 Feb 2023, 17:51
Hellbent wrote:
17 Feb 2023, 13:53
Yes, here it is.
2.0.2 doesn't use the same syntax used in your file. I've got a modified version that works in 2.0.2 almost done. I'm good.
Ok.
I didn't realize that you were talking about ahk v2 lol.

Would you mind sharing your updated version when you are done?

greatwhitepine
Posts: 8
Joined: 16 Feb 2023, 01:24

Re: [class] PopUpWindow (Layered Windows )

Post by greatwhitepine » 20 Feb 2023, 04:08

Hellbent wrote:
18 Feb 2023, 00:09
Would you mind sharing your updated version when you are done?
Not at all though it's a complete rewrite and now one class in a mini gui/component library. It will have library dependencies though I'm trying to make it super easy to use and adapt.

It will be nowhere near complete as far as the component library goes. I only need a few so I'm only adding what I need, mainly edit box (ahk) via GuiBase{} and transparent images (gdi) via the new GdiGui{} which extends GuiBase{}. GdiGui is my name for the gdi Layered Window class. Each component type has it's own class, handlers, etc...

It's going take a bit more setup but promises ease of use, I'm hoping. :-) I'm looking to use it as a base for my first v2 project.

I'll throw it up on github when done. Will post link here.

Post Reply

Return to “Scripts and Functions (v1)”