[Gdip] How to draw lines and retrieve pixel length? Topic is solved

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
User avatar
Scr1pter
Posts: 1271
Joined: 06 Aug 2017, 08:21
Location: Germany

[Gdip] How to draw lines and retrieve pixel length?

08 Jan 2019, 20:05

Hello,

My aim is to be able to draw virtual lines on monitor whenever I activate the function.
By this way I could compare positions of elements in GUIs (not only AHK, also in general).
Right now I always have to take a screenshot, open Paint, pasting it and start drawing lines.

I checked some Gdip tutorials regarding drawing lines.
Additionally I created a function to calculate pixels
and it's possible that a line gets drawn from the start position till the end position.

This is the beta script:

Code: Select all

;Draw lines
^+!F8:: ; Ctrl+Shift+Alt+F8
paintMode := !paintMode ; toggle paint mode (0/1) 
return

#if paintMode ; If paint mode is active:
#include Gdip.ahk ; Include Gdip library
lbutton::
CoordMode, Mouse, Screen ; Absolute position
MouseGetPos, xd, yd ; Retrieve mouse position (pressed/down)
while GetKeyState("lbutton", "P") ; While left mouse buttons is being held:
{ } ; Don't do anything
MouseGetPos, xu, yu ; Retrieve mouse position (released/up)
differenceX := xu - xd ; Calculate difference between both x points
if differenceX < 0 ; If difference is smaller than 0:
{
  differenceX := differenceX * -1 ; Convert it to a natural number -> Can I use some Math function for that?
}
differenceY := yu - yd ; The same for Y
if differenceY < 0
{
  differenceY := differenceY * -1 ;
}
pixel := differenceX + differenceY ; Calculate pixel length
#include gdip-draw-line.ahk ; Draw a line from start position (pressed) till end position (released)
return
The additional script is not mine, I just modified it a little bit:

Code: Select all

GenerateLine: ; Generates a new line
; 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

Width := A_ScreenWidth, Height := A_ScreenHeight ; Set the width and height we want as our drawing area, to draw everything in. This will be the dimensions of our bitmap
Gui, 1: -Caption +E0x80000 +LastFound +OwnDialogs +Owner +AlwaysOnTop ; Create a layered window (+E0x80000: must be used for UpdateLayeredWindow to work!) that is always on top (+AlwaysOnTop), has no taskbar entry or caption
Gui, 1: Show, NA ; Show the window
hwnd1 := WinExist() ; Get a handle to this window we have created in order to update it later
hbm   := CreateDIBSection(Width, Height) ; Create a gdi bitmap with width and height 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
Gdip_SetSmoothingMode(G, 4) ; Set the smoothing mode to antialias = 4 to make shapes appear smother (only used for vector drawing and filling)
pPen := Gdip_CreatePen(0xffff0000, 3) ; Create a fully opaque red pen (ARGB = Transparency, red, green, blue) of width 3 (the thickness the pen will draw at) to draw a line

;Draw Line
Gdip_DrawLine(G, pPen, xd, yd, xu, yu) ; Gdip_DrawLine(pGraphics, pPen, x1, y1, x2, y2), which have been retrieved in the other script
Gdip_DeletePen(pPen) ; Delete the pen as it is no longer needed and wastes memory

; 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
UpdateLayeredWindow(hwnd1, hdc, 0, 0, Width, Height) ; So this will position our gui at (0,0) with the Width and Height specified earlier
return ; I added this return so that it doesn't delete the line
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
Return

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

~*ESC::
Exit:
; gdi+ may now be shutdown on exiting the program
Gdip_Shutdown(pToken)
ExitApp
Return
Now I would like to update the scripts:
- drawing as many lines as I want (until I terminate the function)
- adding the pixel value (doesn't matter where - also in the corner would be ok)
- maybe Gdip can paint it as text?

I tried adding the pixels as Gui text or ToolTips, but it did not work:
If I include the ToolTip or Gui-Text above the gdip function, the gdip function never gets called
If I write it under the gdip function, the ToolTip or Gui-Text never get shown (probably because of the return inside of the gdip-draw-line script)

Code: Select all

; ToolTip, Gui-Text -> Gets shown but Gdip doesn't draw lines
#include gdip-draw-line.ahk ; Draw a line from start position (pressed) till end position (released)
; ToolTip, Gui-Text -> Never gets shown
The result should be like this, but it should be possible to draw endless lines + everytime the pixel values should be drawn "somewhere".
By this way I could easily see if line 1 is as long as line 2, which would mean that objects are alligned correctly.
Image
(In this example I simply drew over the text.)

As said, I use the Paint method sooo often, I would really benefit from some on-screen drawing.

Thanks for any support!

Edit
Changed topic title (added Gdip)

Best regards
Last edited by Scr1pter on 15 Jan 2019, 14:39, edited 2 times in total.
Please use [code][/code] when posting code!
Keyboard: Logitech G PRO - Mouse: Logitech G502 LS - OS: Windows 10 Pro 64 Bit - AHK version: 1.1.33.09
User avatar
Scr1pter
Posts: 1271
Joined: 06 Aug 2017, 08:21
Location: Germany

Re: How to draw lines and retrieve pixel length?

10 Jan 2019, 17:13

Hi guys,

I've made some progress.

I put the Gdip-Draw line functionality inside of my main script.
(If everything works, I can still outsource it.)

What I have changed:
- it's now possible to draw as many lines as I want (the problem was that both guis had the same nr.)
- the pixels get shown in another gui
- instead of if value < 0 { value := value * -1 } I simply use an StrReplace to remove the -

3 things that are still unclear/not working:

1) Graphics probably don't get deleted:
Even though all guis (Instruction gui + layered guis which contain lines) get destroyed,
I'm sceptical if all rest graphics get deleted too.

When I press 4 times the keycombo (enable, disable, enable, disable), it works fine.
When I press it the 5th time, the compiler crashes.

2) Pixels don't get added inside of the instruction Gui
After drawing a new line, the pixel value gets overwritten instead of added (I want pixel1, pixel2, pixel3 etc.)
I thought I had to use .=, but it seems I misunderstood its usage

3) Pixels don't get painted "live"
When holding down the left mouse button, nothing is visible.
Only after releasing it I can see the freshly drawn line.
Sure, it because I programmed it this way, but only because I have no clue how to program it else.
I would like to have it like in Paint where you can clearly see the pixel and still have a chance to correct the line.

At the moment, I have to guess and hope that I've drawn the line correctly.
In Paint I can correct/allign it before releasing the mouse button to make it "final".

--------------------------------------

That's the new version of the script:

Code: Select all

;Draw lines
^+!F8:: ; Ctrl+Shift+Alt+F8
if paintMode ; If paint mode is already active:
{
  Gui_Anweisungen(0, "", "", "", "") ; Fade-Out instruction GUI
  paintMode := !paintMode ; Turn off paint mode (0)
  SelectObject(hdc, obm) ; Select the object back into the hdc - NO IDEA IF IT WORKS!
  DeleteObject(hbm) ; Now the bitmap may be deleted - NO IDEA IF IT WORKS!
  Gdip_DeletePen(pPen) ; Delete the pen as it is no longer needed and wastes memory - NO IDEA IF IT WORKS!
  DeleteDC(hdc) ; Also the device context related to the bitmap may be deleted - NO IDEA IF IT WORKS!
  Gdip_DeleteGraphics(G) ; The graphics may now be deleted - NO IDEA IF IT WORKS!
  Gdip_Shutdown(pToken) ; - NO IDEA IF IT WORKS!
  Loop, %i% ; Repeat as many times as number of guis 
  {
    Gui, %A_Index%: Destroy ; Destroy all guis which have been created recently
  }
  i = 0 ; Reset incrementer
}
else ; If it's not active:
{
  paintMode := !paintMode ; Turn on paintMode (1)
  Gui_Anweisungen(1, "Paint mode", "Instructions:", "Draw a line!", "Press Ctrl+Shift+Alt+F8 to exit") ; Fade-in instruction GUI
  pToken := Gdip_Startup() ; Start gdip instance
}
return

#if paintMode ; If paint mode is active:
#include Guis\Gui-Anweisungen.ahk ; Include GUI
#include Gdip.ahk ; Include Gdip library

lbutton::
i++ ; incrementer for each mouse click
CoordMode, Mouse, Screen ; Absolute position
MouseGetPos, xd, yd ; Retrieve mouse position (pressed/down)
while GetKeyState("lbutton", "P") ; While left mouse buttons is being held:
{ } ; Don't do anything
MouseGetPos, xu, yu ; Retrieve mouse position (released/up)
differenceX := xu - xd ; Calculate difference between both x points
differenceX := StrReplace(differenceX, "-") ; If it's a negative number, convert it to a positive one.
differenceY := yu - yd ; Calculate difference between both y points
differenceY := StrReplace(differenceY, "-") ; If it's a negative number, convert it to a positive one.
pixel       := differenceX + differenceY ; Calculate pixel length
pixel .= pixel . "`," ; Add new pixel value to old one, separate them by , -> DOESN'T WORK, OLD PIXEL VALUE GETS OVERWRITTEN
Width := A_ScreenWidth, Height := A_ScreenHeight ; Set the width and height we want as our drawing area, to draw everything in. This will be the dimensions of our bitmap
Gui, %i%: -Caption +E0x80000 +LastFound +OwnDialogs +Owner +AlwaysOnTop ; Create a layered window (+E0x80000: must be used for UpdateLayeredWindow to work!) that is always on top (+AlwaysOnTop), has no taskbar entry or caption
Gui, %i%: Show, NA ; Show the window which contains the freshly drawn line (without activating it)
hwnd := WinExist() ; Get a handle to this window we have created in order to update it later
hbm  := CreateDIBSection(Width, Height) ; Create a gdi bitmap with width and height 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
Gdip_SetSmoothingMode(G, 4) ; Set the smoothing mode to antialias = 4 to make shapes appear smother (only used for vector drawing and filling)
pPen := Gdip_CreatePen(0xffff0000, 3) ; Create a fully opaque red pen (ARGB = Transparency, red, green, blue) of width 3 (the thickness the pen will draw at) to draw a line
Gdip_DrawLine(G, pPen, xd, yd, xu, yu) ; Gdip_DrawLine(pGraphics, pPen, x1, y1, x2, y2), which have been set by using left mouse button
UpdateLayeredWindow(hwnd, hdc, 0, 0, Width, Height) ; So this will position our gui at (0,0) with the Width and Height specified earlier
Gui_Text_Aendern("Pixel:", "schritte", pixel, "anweisungen") ; Update instruction GUI with new pixels
return
#if ; Close #if-block
This is how it looks like at the moment:
Image

Thanks for any help!

Best regards
Please use [code][/code] when posting code!
Keyboard: Logitech G PRO - Mouse: Logitech G502 LS - OS: Windows 10 Pro 64 Bit - AHK version: 1.1.33.09
User avatar
Scr1pter
Posts: 1271
Joined: 06 Aug 2017, 08:21
Location: Germany

Re: How to draw lines and retrieve pixel length?

15 Jan 2019, 14:33

Hey guys,

Fortunately, I've made some further progress.
I don't give up so quickly!

Code: Select all

^+!F8:: ; Ctrl+Shift+Alt+F8
if paintMode ; If paint mode is already active:
{
  Gui_Anweisungen(0, "", "", "", "") ; Fade-Out instruction GUI
  paintMode := !paintMode ; Turn off paint mode (0)
  SelectObject(hdc, obm) ; Select the object back into the hdc - NO IDEA IF IT WORKS!
  DeleteObject(hbm) ; Now the bitmap may be deleted - NO IDEA IF IT WORKS!
  Gdip_DeletePen(pPen) ; Delete the pen as it is no longer needed and wastes memory - NO IDEA IF IT WORKS!
  DeleteDC(hdc) ; Also the device context related to the bitmap may be deleted - NO IDEA IF IT WORKS!
  Gdip_DeleteGraphics(G) ; The graphics may now be deleted - NO IDEA IF IT WORKS!
  Gdip_Shutdown(pToken) ; - NO IDEA IF IT WORKS!
  Loop, %i% ; Repeat as many times as number of guis 
  {
    Gui, %A_Index%: Destroy ; Destroy all guis which have been created recently
  }
  i = 0 ; Reset incrementer
}
else ; If it's not active:
{
  paintMode := !paintMode ; Turn on paintMode (1)
  Gui_Anweisungen(1, "Paint mode", "Instructions:", "Draw a line!", "Press Ctrl+Shift+Alt+F8 to exit") ; Fade-in instruction GUI
  pToken := Gdip_Startup() ; Start gdip instance
}
return

Code: Select all

#if paintMode ; If paint mode is active:
#include Guis\Gui-Anweisungen.ahk ; Include GUI
#include Gdip.ahk ; Include Gdip library

lbutton::
i++ ; incrementer for each mouse click
CoordMode, Mouse, Screen ; Absolute position
MouseGetPos, xStart, yStart ; Retrieve mouse position (pressed/down)

Width := A_ScreenWidth, Height := A_ScreenHeight ; Set the width and height we want as our drawing area, to draw everything in. This will be the dimensions of our bitmap
Gui, %i%: -Caption +E0x80000 +LastFound +OwnDialogs +Owner +AlwaysOnTop ; Create a layered window (+E0x80000: must be used for UpdateLayeredWindow to work!) that is always on top (+AlwaysOnTop), has no taskbar entry or caption
Gui, %i%: Show, NA ; Show the window which contains the freshly drawn line (without activating it)
hwnd := WinExist() ; Get a handle to this window we have created in order to update it later
hbm  := CreateDIBSection(Width, Height) ; Create a gdi bitmap with width and height 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
Gdip_SetSmoothingMode(G, 4) ; Set the smoothing mode to antialias = 4 to make shapes appear smother (only used for vector drawing and filling)
pPen := Gdip_CreatePen(0xffff0000, 3) ; Create a fully opaque red pen (ARGB = Transparency, red, green, blue) of width 3 (the thickness the pen will draw at) to draw a line

while GetKeyState("lbutton", "P") ; While left mouse buttons is being held:
{ 
  MouseGetPos, xCurrent, yCurrent ; Retrieve current mouse position
  Gdip_DrawLine(G, pPen, xStart, yStart, xCurrent, yCurrent) ; Gdip_DrawLine(pGraphics, pPen, x1, y1, x2, y2), which have been set by using left mouse button
  UpdateLayeredWindow(hwnd, hdc, 0, 0, Width, Height) ; So this will position our gui at (0,0) with the Width and Height specified earlier
}
return
Now it seems possible that the lines get updated.
However, I'm unable to delete the last drawn line.

For this reason, the result looks very strange:
Image

How to code it so that it behaves exactly as Microsoft Paint?
Doesn't matter what I draw, there should be only 1 line
(unless I release the left button and start drawing another line - as in the GIF)

My idea was:
if xCurrent or yCurrent change their values, the graphics should be deleted and redrawn.
But generally it might be safer to constantly delete and redraw them.
I putted some of the elements (which get called to delete graphics) inside of the while loop,
but the result was always no line.

Thanks for any help!

Cheers!
Please use [code][/code] when posting code!
Keyboard: Logitech G PRO - Mouse: Logitech G502 LS - OS: Windows 10 Pro 64 Bit - AHK version: 1.1.33.09
User avatar
Hellbent
Posts: 2102
Joined: 23 Sep 2017, 13:34

Re: [Gdip] How to draw lines and retrieve pixel length?

15 Jan 2019, 17:46

Here is a script that I made a while back to play around with drawing on the screen.
I think I had the same issue as you with the lines being drawn from the origin point over and over so I just updated the start point to be my current position each frame. You should note that this is just a script to play around with things and that it was when I was still very new to using gdip.

Code: Select all

#SingleInstance, Force
Coordmode,Mouse,Screen
#NoEnv
Gdip_Startup()
OnExit, Exit
Width :=A_ScreenWidth, Height :=A_ScreenHeight
Gui, 1: -Caption +E0x80000 +LastFound +AlwaysOnTop +ToolWindow +OwnDialogs
Gui, 1: Show, NA
hwnd1 := WinExist(),hbm := CreateDIBSection(Width, Height),hdc := CreateCompatibleDC(),obm := SelectObject(hdc, hbm),G := Gdip_GraphicsFromHDC(hdc)
Gdip_SetSmoothingMode(G, 4)
UpdateLayeredWindow(hwnd1, hdc, 0, 0, Width, Height)
color1:="0xff000000",i:=0,j:=0
Return
Timer:
	If(GetKeyState("Ctrl")){
		MouseGetPos,x1,y1
		pPen := Gdip_CreatePen(color1, 3)
		Gdip_DrawLine(G, pPen,xStart,yStart, x1, y1)
		Gdip_DeleteBrush(pPen)
		pPen := Gdip_CreatePen(color1, 3)
		Gdip_DrawLine(G, pPen,xStart-1,yStart-1, x1-1, y1-1)
		Gdip_DeleteBrush(pPen)
		pPen := Gdip_CreatePen(color1, 3)
		Gdip_DrawLine(G, pPen,xStart+1,yStart+1, x1+1, y1+1)
		Gdip_DeleteBrush(pPen)
		UpdateLayeredWindow(hwnd1, hdc, 0, 0, Width, Height)
		xStart:=x1,yStart:=y1
	}else
		SetTimer,Timer,Off
	return
*^LButton::
	MouseGetPos,xStart,yStart
	SetTimer,Timer,10
	return
*^RButton::
	Gui,1:Destroy
	Width :=A_ScreenWidth, Height :=A_ScreenHeight
	Gui, 1: -Caption +E0x80000 +LastFound +AlwaysOnTop +ToolWindow +OwnDialogs
	Gui, 1: Show, NA
	hwnd1 := WinExist()
	SelectObject(hdc, obm)
	DeleteObject(hbm)
	DeleteDC(hdc)
	Gdip_DeleteGraphics(G)
	hbm := CreateDIBSection(Width, Height),hdc := CreateCompatibleDC(),obm := SelectObject(hdc, hbm),G := Gdip_GraphicsFromHDC(hdc)
	Gdip_SetSmoothingMode(G, 4)
	return
Update_Color:
	Gui,2:Submit
	tlist:=["0xff000000","0xffff0000","0xff0000ff","0xff00ff00","0xff00ffff","0xffffff00","0xffff00ff"],Color1:=tList[tColor1-1]
	Gui,2:Destroy
	return
^WheelUp::
^WheelDown::
	Gui,2:Destroy
	Gui,2:+AlwaysOnTop -Caption 
	Gui,2:Add,ListBox,x0 y0 w200 r10 AltSubmit vtColor1 gUpdate_Color,|Black||Red|Blue|Green|Aqua|Yellow|Purple
	Gui,2:Show
	return
Exit:
*^NumPad7::
Gdip_Shutdown(pToken)
ExitApp
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)
}
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
}
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)
}
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_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_GraphicsFromHDC(hdc)
{
    DllCall("gdiplus\GdipCreateFromHDC", A_PtrSize ? "UPtr" : "UInt", hdc, A_PtrSize ? "UPtr*" : "UInt*", pGraphics)
    return pGraphics
}
Gdip_CreatePen(ARGB, w)
{
   DllCall("gdiplus\GdipCreatePen1", "UInt", ARGB, "float", w, "int", 2, A_PtrSize ? "UPtr*" : "UInt*", pPen)
   return pPen
}

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_DeleteGraphics(pGraphics)
{
   return DllCall("gdiplus\GdipDeleteGraphics", A_PtrSize ? "UPtr" : "UInt", pGraphics)
}
Gdip_SetSmoothingMode(pGraphics, SmoothingMode)
{
   return DllCall("gdiplus\GdipSetSmoothingMode", A_PtrSize ? "UPtr" : "UInt", pGraphics, "int", SmoothingMode)
}
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_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
}


I do have a bit of experience working with gdip now, but your post is a bit of a wall and I am having a hard time following it (rather I'm having a hard time forcing myself to actually read it). with that said, help me out by zeroing in on what you want and I might? be able to assist.
User avatar
Scr1pter
Posts: 1271
Joined: 06 Aug 2017, 08:21
Location: Germany

Re: [Gdip] How to draw lines and retrieve pixel length?

15 Jan 2019, 18:30

Hi and thanks for your answer!

Your script is indeed interesting.
I tried it out and it's pretty good.

Well, basically I simply need a way to draw lines like in MS Paint
Image

With your script it's perfectly possible to draw.
(Same as if I draw in Paint by using the pen.)

If we could somehow update your script so that it only draws lines, it will be perfect for me.
Important is that I have the ability to modify the line (the same ways as in the GIF.)

The rest with counting pixels already works - you can ignore that part.

Cheers!
Please use [code][/code] when posting code!
Keyboard: Logitech G PRO - Mouse: Logitech G502 LS - OS: Windows 10 Pro 64 Bit - AHK version: 1.1.33.09
User avatar
Hellbent
Posts: 2102
Joined: 23 Sep 2017, 13:34

Re: [Gdip] How to draw lines and retrieve pixel length?

15 Jan 2019, 18:57

This is not complete to your end goal, but it is the first step.

Run this (It may error because of the wrapper I use but we can deal with that if it is a issue)

once the script is running, press ctrl + LButton to start drawing a line, then press shift to stop drawing

Code: Select all

#SingleInstance, Force
SetBatchLines,-1
OnExit,GuiClose
CoordMode,Mouse,Client

global MyGui := {W: 600 ,H: 600 }
global GdipOBJ:={X: 0 ,Y: 0 ,W: MyGui.W ,H: MyGui.H }
global active_Draw:=0


Gui,1:+AlwaysOnTop -DPIScale
Gui,1:Color,222222
Gui,1:Show,% "w" MyGui.W " h" MyGui.H
GdipOBJ := Layered_Window_SetUp(4,GdipOBJ.X,GdipOBJ.Y,GdipOBJ.W,GdipOBJ.H,2,"-Caption -DPIScale +Parent1")
UpdateLayeredWindow(GdipOBJ.hwnd, GdipOBJ.hdc, GdipOBJ.X, GdipOBJ.Y, GdipOBJ.W, GdipOBJ.H)
MyPen:=New_Pen("FF0000",,5)




return
GuiClose:
*^ESC::
	Layered_Window_ShutDown(GdipOBJ)
	ExitApp


DrawStuff:
	Gdip_GraphicsClear(GdipOBJ.G)
	MouseGetPos,ex,ey
	Gdip_DrawLine(GdipOBJ.G, myPen, sx, sy, ex, ey)
	UpdateLayeredWindow(GdipOBJ.hwnd, GdipOBJ.hdc)
	if(GETKEYSTATE("Shift")){
		active_Draw:=0
		SetTimer,DrawStuff,off
		tooltip,% "The lenght is " abs(Sqrt(((sx-ex)**2) + ((sy-ey)**2)))
		Gdip_DeletePen(myPen)
	}
	return
	



#If (active_Draw=0)
*^LButton::
	active_Draw:=1
	MyPen:=New_Pen("FF0000",,5)
	MouseGetPos,sx,sy
	SetTimer,DrawStuff,10
	return
#If



   ;GDIP Stuff

;--------------------------------------------------------------------------------------------------------------
;--------------------------------------------------------------------------------------------------------------
;--------------------------------------------------------------------------------------------------------------
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_DeleteBrush(pBrush)
{
   return DllCall("gdiplus\GdipDeleteBrush", A_PtrSize ? "UPtr" : "UInt", pBrush)
}
Gdip_DeletePen(pPen)
{
   return DllCall("gdiplus\GdipDeletePen", A_PtrSize ? "UPtr" : "UInt", pPen)
}
Gdip_DisposeImage(pBitmap)
{
   return DllCall("gdiplus\GdipDisposeImage", A_PtrSize ? "UPtr" : "UInt", pBitmap)
}
Layered_Window_ShutDown(This)
	{
		SelectObject(This.hdc,This.obm)
		DeleteObject(This.hbm)
		DeleteDC(This.hdc)
		gdip_deleteGraphics(This.g)
		Gdip_Shutdown(This.Token)
	}
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)
}
DeleteObject(hObject)
{
   return DllCall("DeleteObject", A_PtrSize ? "UPtr" : "UInt", hObject)
}
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_GraphicsFromImage(pBitmap)
{
	DllCall("gdiplus\GdipGetImageGraphicsContext", A_PtrSize ? "UPtr" : "UInt", pBitmap, A_PtrSize ? "UPtr*" : "UInt*", pGraphics)
	return pGraphics
}
Gdip_SetSmoothingMode(pGraphics, SmoothingMode)
{
   return DllCall("gdiplus\GdipSetSmoothingMode", A_PtrSize ? "UPtr" : "UInt", pGraphics, "int", SmoothingMode)
}
New_Brush(colour:="000000",Alpha:="FF")
	{
		;~ static Hellbent_Brush:=[]
		new_colour := "0x" Alpha colour 
		;~ Hellbent_Brush[Hellbent_Brush.Length()+1]:=Gdip_BrushCreateSolid(new_colour)
		return Gdip_BrushCreateSolid(new_colour)
	}
Fill_Box(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_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_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_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_DeleteGraphics(pGraphics)
{
   return DllCall("gdiplus\GdipDeleteGraphics", A_PtrSize ? "UPtr" : "UInt", pGraphics)
}
Layered_Window_SetUp(Smoothing,Window_X,Window_Y,Window_W,Window_H,Window_Name:=1,Window_Options:="")
	{
		Layered:={}
		Layered.W:=Window_W
		Layered.H:=Window_H
		Layered.X:=Window_X
		Layered.Y:=Window_Y
		Layered.Name:=Window_Name
		Layered.Options:=Window_Options
		Layered.Token:=Gdip_Startup()
		Create_Layered_GUI(Layered)
		Layered.hwnd:=winExist()
		Layered.hbm := CreateDIBSection(Window_W,Window_H)
		Layered.hdc := CreateCompatibleDC()
		Layered.obm := SelectObject(Layered.hdc,Layered.hbm)
		Layered.G := Gdip_GraphicsFromHDC(Layered.hdc)
		Gdip_SetSmoothingMode(Layered.G,Smoothing)
		return Layered
	}
Gdip_GraphicsClear(pGraphics, ARGB=0x00ffffff)
{
    return DllCall("gdiplus\GdipGraphicsClear", A_PtrSize ? "UPtr" : "UInt", pGraphics, "int", ARGB)
}
New_Pen(colour:="000000",Alpha:="FF",Width:= 5)
	{
		;~ static Hellbent_Pen:=[]
		new_colour := "0x" Alpha colour 
		;~ Hellbent_Pen[Hellbent_Pen.Length()+1]:=Gdip_CreatePen(New_Colour,Width)
		return Gdip_CreatePen(New_Colour,Width)
	}
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_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_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_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)
}
SelectObject(hdc, hgdiobj)
{
	Ptr := A_PtrSize ? "UPtr" : "UInt"
	
	return DllCall("SelectObject", Ptr, hdc, Ptr, hgdiobj)
}
DeleteDC(hdc)
{
   return DllCall("DeleteDC", A_PtrSize ? "UPtr" : "UInt", hdc)
}
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_BrushCreateSolid(ARGB=0xff000000)
{
	DllCall("gdiplus\GdipCreateSolidFill", "UInt", ARGB, 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_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_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_StringFormatCreate(Format=0, Lang=0)
{
   DllCall("gdiplus\GdipCreateStringFormat", "int", Format, "int", Lang, A_PtrSize ? "UPtr*" : "UInt*", hFormat)
   return hFormat
}
Gdip_SetStringFormatAlign(hFormat, Align)
{
   return DllCall("gdiplus\GdipSetStringFormatAlign", A_PtrSize ? "UPtr" : "UInt", hFormat, "int", Align)
}
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
}
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_DeleteStringFormat(hFormat)
{
   return DllCall("gdiplus\GdipDeleteStringFormat", A_PtrSize ? "UPtr" : "UInt", hFormat)
}
Gdip_DeleteFont(hFont)
{
   return DllCall("gdiplus\GdipDeleteFont", A_PtrSize ? "UPtr" : "UInt", hFont)
}
Gdip_DeleteFontFamily(hFamily)
{
   return DllCall("gdiplus\GdipDeleteFontFamily", A_PtrSize ? "UPtr" : "UInt", hFamily)
}
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_DisposeImageAttributes(ImageAttr)
{
	return DllCall("gdiplus\GdipDisposeImageAttributes", A_PtrSize ? "UPtr" : "UInt", ImageAttr)
}
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
}
Create_Layered_GUI(Layered)
	{
		Gui,% Layered.Name ": +E0x80000 +LastFound " Layered.Options 
		Gui,% Layered.Name ":Show",% "x" Layered.X " y" Layered.Y " w" Layered.W " h" Layered.H " NA"
	}
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
}
CreateCompatibleDC(hdc=0)
{
   return DllCall("CreateCompatibleDC", A_PtrSize ? "UPtr" : "UInt", hdc)
}
Gdip_GraphicsFromHDC(hdc)
{
    DllCall("gdiplus\GdipCreateFromHDC", A_PtrSize ? "UPtr" : "UInt", hdc, A_PtrSize ? "UPtr*" : "UInt*", pGraphics)
    return pGraphics
}
Gdip_CreatePen(ARGB, w)
{
   DllCall("gdiplus\GdipCreatePen1", "UInt", ARGB, "float", w, "int", 2, A_PtrSize ? "UPtr*" : "UInt*", pPen)
   return pPen
}
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_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_SetClipRegion(pGraphics, Region, CombineMode=0)
{
	Ptr := A_PtrSize ? "UPtr" : "UInt"
	
	return DllCall("gdiplus\GdipSetClipRegion", Ptr, pGraphics, Ptr, Region, "int", CombineMode)
}
Gdip_DeleteRegion(Region)
{
	return DllCall("gdiplus\GdipDeleteRegion", A_PtrSize ? "UPtr" : "UInt", Region)
}
Gdip_ResetClip(pGraphics)
{
   return DllCall("gdiplus\GdipResetClip", A_PtrSize ? "UPtr" : "UInt", pGraphics)
}
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)
}
GetDC(hwnd=0)
{
	return DllCall("GetDC", A_PtrSize ? "UPtr" : "UInt", hwnd)
}
ReleaseDC(hdc, hwnd=0)
{
	Ptr := A_PtrSize ? "UPtr" : "UInt"
	
	return DllCall("ReleaseDC", Ptr, hwnd, Ptr, hdc)
}
Gdip_CreateRegion()
{
	DllCall("gdiplus\GdipCreateRegion", "UInt*", Region)
	return Region
}
User avatar
FanaticGuru
Posts: 1906
Joined: 30 Sep 2013, 22:25

Re: [Gdip] How to draw lines and retrieve pixel length?  Topic is solved

15 Jan 2019, 19:15

A script on the forums called Compass might be useful to look at.

https://www.autohotkey.com/boards/viewtopic.php?t=7225

It draws a line and lets you measure between two points. It erases each line after drawing but it is close.

It looks like it draws the line and then erases with DllCall("gdiplus.dll\GdipGraphicsClear", "Ptr", G, "UInt", 0x00FFFFFF) over an over very fast. But the erase does not take effect until the UpdateLayeredWindow which by that time a new line is draw.

Draw line, update, erase line, repeat...

It also uses direct DllCall to all the Gdip stuff so doesn't need Gdip library. That can be pretty complicated to work with though. Back to the days before Gdip library when you really had to know your variable types to draw. Most of the DllCall commands are the same as methods in Gdip library just without all the nice wrappers.

FG
Hotkey Help - Help Dialog for Currently Running AHK Scripts
AHK Startup - Consolidate Multiply AHK Scripts with one Tray Icon
Hotstring Manager - Create and Manage Hotstrings
[Class] WinHook - Create Window Shell Hooks and Window Event Hooks
User avatar
Scr1pter
Posts: 1271
Joined: 06 Aug 2017, 08:21
Location: Germany

Re: [Gdip] How to draw lines and retrieve pixel length?

15 Jan 2019, 19:38

@Hellbent:
Thanks for this huge script!

I tried it out (just added F4:: to start it), but unfortunately it does not run:
Error: Could not create window.
It has problems with this line:
Gui,% Layered.Name ": +E0x80000 +LastFound " Layered.Options

The Gui is opened, though.
When I click inside of it, I see nothing but at least it says "the lenght is..."

@FG:
I will check it out tomorrow and let you know.
Thanks for your support as well. :)

Cheers!
Please use [code][/code] when posting code!
Keyboard: Logitech G PRO - Mouse: Logitech G502 LS - OS: Windows 10 Pro 64 Bit - AHK version: 1.1.33.09
User avatar
Hellbent
Posts: 2102
Joined: 23 Sep 2017, 13:34

Re: [Gdip] How to draw lines and retrieve pixel length?

15 Jan 2019, 19:59

Scr1pter wrote:
15 Jan 2019, 19:38
It has problems with this line:
Gui,% Layered.Name ": +E0x80000 +LastFound " Layered.Options
Ok, you are the second person that has had a issue using my setup wrapper, I don't know why it errors for you but oh well.

The work around is for you to strip everything out of the script and just look at the DrawStuff timed subroutine.

You can use your setup that you had before.
Then you just need to replace my New_Pen() function with the normal gdip function to create a new pen.

You can also do away with having a timer at all and just put a while loop in your hotkey. I don't like using hotkeys (the irony is not lost on me) so I don't use them often.

So, the important thing is that at the beginning of each loop you clear the graphics and then draw the line again, over and over until you have set your end point.


As for drawing multiple lines, you will need to create a array of objects (or something similar) to hold the positions of your lines.

So once you end your line you will take the sx,sy,ex,ey and put them into one of your array of objects.
In your loop, after you clear the screen you draw the line you are working on just as it is in the script now, but you also loop over your array and draw them too.

Pseudo code:

Code: Select all

DrawStuff:
	Gdip_GraphicsClear(GdipOBJ.G)  ; your G replaces GdipOBJ.G
	MouseGetPos,ex,ey
	Gdip_DrawLine(GdipOBJ.G, myPen, sx, sy, ex, ey)  ; Your G
	loop,% MyArray.Length()	{
		Gdip_DrawLine(GdipOBJ.G, myPen, MyArray[A_Index].sx, MyArray[A_Index].sy, MyArray[A_Index].ex, MyArray[A_Index].ey)  ;Your G replaces GdipOBJ.G
	}
	UpdateLayeredWindow(GdipOBJ.hwnd, GdipOBJ.hdc)   ; your hwnd and hdc
	if(GETKEYSTATE("Shift")){
		active_Draw:=0
		SetTimer,DrawStuff,off
		tooltip,% "The length is " abs(Sqrt(((sx-ex)**2) + ((sy-ey)**2)))
		Gdip_DeletePen(myPen)
		MyArray[MyArray.Lenght()+1]:={sx:sx,sy:sy,ex:ex,ey:ey}
	}
	return
User avatar
Hellbent
Posts: 2102
Joined: 23 Sep 2017, 13:34

Re: [Gdip] How to draw lines and retrieve pixel length?

15 Jan 2019, 20:18

Here is a script that has some of the elements that you are looking for.

When you press the set position button it starts drawing a few lines, then when you press the left mouse it keeps drawing the old lines but also starts drawing new ones.

The code you will be looking for starts on line 312 in the SPOS() function and ends with the hotkey a few lines below that.
It's not exactly what you are trying to do, but it is hella close, and I didn't use my wrapper function in this script.

Run this and press the "set position button" , it only draws on your main screen.

Code: Select all

/*
	Written By: Hellbent aka CivReborn (YouTube)
	Date Started: Dec 6th, 2018
	Date of last edit: Dec 16th, 2018
	Pixel Predator pixel search script. v1.0.1
	First Pastebin Copy:    https://pastebin.com/6pyq12fB
	Newest Pastebin Copy:   https://pastebin.com/raw/6pyq12fB
*/
SetUp()
pButton_StartUp() 
global pButton:={},pCheckBox:={},pRadio:={},Press_active:=0,Hover_On:=0,Active_Button,Pos_Setting_Active:=0,Variation:=0,Color_Edit:="0x7200FF",Stop:=1,cx2:="",cy2:="",X_Pos:="",Y_Pos:="",Active:=0
,Tips_Text:="Format`n *Click or Move*Number of clicks*X position offset*Y position offset*What mouse Button*loop*Normal Send Command `n The following is an example of setting up to click 1 time per loop with a x and y offset of 10px clicking with the left mouse button and having it loop`n`n*1*1*10*10*Left*1*"
global Commands:="",x,y,Delay:=150,M_Delay:=100,cx:="",cy:="",Key_Delay:=150
tips_Text =
(% ` Join`r`n
	Format: *1*2*3*4*5*6*7*8*9*10
	
			*1*	-----	Turn On/Off Search Loop (Values: 0 [Don't loop]  , 1 [Loop Forever])
			*2*		Click or Move (Range: 0-1)
			*3*		Number of clicks per loop (Range 1+)
			*4*	-----	X-Offset 
			*5*		Y-Offset
			*6*	-----	Which Mouse Button to use  (Values: L , M , R )
			*7* 	-----	Amount of time a click is held (in ms)
			*8*		Amount of time between key strokes (in ms)
			*9*	-----	How long to wait between click loops (in ms)
			*10		Commands to "send" (e.g. {Enter} r) See Documentation For List of values
			
	Set *2*3* both to a value of 0 to disable click / move 
	
	Set *1*2*3* all to a value of 0 to loop once with click /move disabled
	
	
	
)
Build_GUI()
return

GuiClose:
	GDip_Shutdown(pToken)
	ExitApp
SetUp(){
	global
	#SingleInstance,Force
	SetBatchLines,-1
	SetMouseDelay,M_Delay
	SetDefaultMouseSpeed,0
	SetKeyDelay,Key_Delay ,10
	Coordmode,Mouse,Screen
	Coordmode,Pixel,Screen
	SetControlDelay, -1
	ListLines,off
	OnExit,GuiClose
}
Build_GUI(){
	global
	Gui_Width:=450,Gui_Height:=300,Shadow_Color:=888888,Shadow_Color3:=000000,Shadow_Color2:="Black",Selected_Color:="7200FF"
	Gui,1:+AlwaysOnTop -DPIScale -Caption
	Gui,1:Color,222222
	Gui,1:Font,cBlack s10 Bold Q5,Segoe UI 
	Gui,1:Add,Progress,x0 y0 w%Gui_Width% h2 Background%Shadow_Color% c%Shadow_Color%,100
	Gui,1:Add,Progress,x0 y0 w2 h%Gui_Height% Background%Shadow_Color% c%Shadow_Color%,100
	Gui,1:Add,Progress,x0 y298 w%Gui_Width% h2 Background%Shadow_Color3% c%Shadow_Color3%,100
	Gui,1:Add,Progress,x448 y0 w2 h%Gui_Height% Background%Shadow_Color3% c%Shadow_Color3%,100
	pButton.Push(New Progress_Button("1",pButton.Length()+1,"Tag",6,6,25,25,"PURPLE","888888","7200FF","B400FF","B400FF","HB",4))
	Gui,1:Font,cBlack s14 Q5,Segoe UI 
	pButton.Push(New Progress_Button("1",pButton.Length()+1,"Win_Move",80,6,290,30,"PURPLE","888888","7200FF","B400FF","red","Pixel Predator",3))
	Gui,1:Font,cBlack s10  Q5,Segoe UI 
	pButton.Push(New Progress_Button("1",pButton.Length()+1,"Win_Min",410,5,15,15,"PURPLE","888888","7200FF","B400FF","red","_",-4))
	pButton.Push(New Progress_Button("1",pButton.Length()+1,"GuiClose",430,5,15,15,"PURPLE","888888","7200FF","ff0000","red","X",-1))
	Gui,1:Show,w%Gui_Width% h%Gui_Height%,Pixel Clicker v1.0.1
	Gui,2:+AlwaysOnTop -Caption -DPIScale +Parent1
	Gui,2:Color,333333 ,Black
	Gui,2:Add,Progress,x0 y0 w%Gui_Width% h3 Background%Shadow_Color2% c%Shadow_Color2%,100
	Gui,2:Add,Progress,x0 y0 w3 h%Gui_Height% Background%Shadow_Color2% c%Shadow_Color2%,100
	Gui,2:Add,Progress,x2 y248 w%Gui_Width% h3 Background%Shadow_Color% c%Shadow_Color%,100
	Gui,2:Add,Progress,x428 y2 w3 h%Gui_Height% Background%Shadow_Color% c%Shadow_Color%,100
	Gui,2:Font,cBlack s10 bold,Segoe UI  
	Gui,2:Add,Progress,x10 y5 w410 h5 Background5618E4 c000000,100
	Gui,2:Add,Progress,x10 y50 w410 h5 Background5618E4 c000000,100
	Gui,2:Add,Progress,x10 y95 w410 h5 Background5618E4 c000000,100
	Gui,2:Add,Progress,x10 y140 w410 h5 Background5618E4 c000000,100
	Gui,2:Add,Progress,x10 y180 w410 h5 Background5618E4 c000000,100
	Gui,2:Font,cBlack s10 Q5,Segoe UI Black
	pButton.Push(New Progress_Button("2",pButton.Length()+1,"Get_Color",30,15,110,30,"Black","bbbbbb","5618E4","7200FF","aa00ff","Set Colour",6))
	Gui,2:Add,Progress,x150 y15 w50 h30 BackgroundBlack c%Selected_Color% vSelected_Color,100
	pButton.Push(New Progress_Button("2",pButton.Length()+1,"Set_Position",20,60,110,30,"Black","bbbbbb","5618E4","7200FF","aa00ff","Set Position",6))
	Gui,2:Font,cWhite s10 Q5,Segoe UI
	Gui,2:Add,Edit,x210 y20 w80 h20 -E0x200 vColor_Edit gSubmit_All,% Color_Edit
	Gui,2:Add,Text,x300 y20 w40 h20 0x200 ,Var:
	Gui,2:Add,Edit,x340 y20 w40 h20 -E0x200 vVariation gSubmit_All,0
	Gui,2:Add,Text,x140 y65 w20 h20 0x200,X:
	Gui,2:Add,Edit,x160 y65 w40 h20 -E0x200 Number vX_Pos gSubmit_All
	Gui,2:Add,Text,x210 y65 w20 h20 0x200,Y:
	Gui,2:Add,Edit,x230 y65 w40 h20 -E0x200 Number vY_Pos gSubmit_All
	Gui,2:Add,Text,x280 y65 w20 h20 0x200,W:
	Gui,2:Add,Edit,x300 y65 w40 h20 -E0x200 Number vW_Pos gSubmit_All
	Gui,2:Add,Text,x350 y65 w20 h20 0x200,H:
	Gui,2:Add,Edit,x370 y65 w40 h20 -E0x200 Number vH_Pos gSubmit_All
	Gui,2:Font,cBlack s10 Q5,Segoe UI
	pRadio[1]:=New Progress_Radio(2,"Set_True","Set_Truth",1,"Truth",20,110,100,20,-62,1,"White","Black","5618E4","222222","True",1,1)
	pRadio[2]:=New Progress_Radio(2,"Set_False","Set_Truth",0,"Truth",130,110,100,20,-64,1,"White","Black","5618E4","222222","False",1,1)
	pButton.Push(New Progress_Button("2",pButton.Length()+1,"AHK_Send_Page",255,105,150,30,"Black","bbbbbb","5618E4","7200FF","aa00ff","Documentation",6))
	Gui,2:Font,cWhite s8 Q5,Segoe UI
	Gui,2:Add,Edit,x20 y148 w276 h30 -E0x200 -VScroll vCommands gSubmit_All,
	Gui,2:Font,cBlack s10 Q5,Segoe UI
	pButton.Push(New Progress_Button("2",pButton.Length()+1,"Defall",306,151,24,24,"Black","bbbbbb","5618E4","7200FF","aa00ff","C",4))
	pButton.Push(New Progress_Button("2",pButton.Length()+1,"DefallM",336,151,24,24,"Black","bbbbbb","5618E4","7200FF","aa00ff","M",4))
	pButton.Push(New Progress_Button("2",pButton.Length()+1,"DefallT",366,151,24,24,"Black","bbbbbb","5618E4","7200FF","aa00ff","T",4))
	pButton.Push(New Progress_Button("2",pButton.Length()+1,"Tips",396,151,24,24,"Black","bbbbbb","5618E4","7200FF","aa00ff","?",4))
	pButton.Push(New Progress_Button("2",pButton.Length()+1,"Start_Search",10,190,130,30,"Black","bbbbbb","5618E4","7200FF","aa00ff","Start",6))
	pButton.Push(New Progress_Button("2",pButton.Length()+1,"Stop_Search",150,190,130,30,"Black","bbbbbb","5618E4","7200FF","aa00ff","Stop",6))
	pButton.Push(New Progress_Button("2",pButton.Length()+1,"Reload",290,190,130,30,"Black","bbbbbb","5618E4","7200FF","aa00ff","Reload",6))
	Gui,2:Font,cWhite s10 Q5,Segoe UI
	Gui,2:Add,Text,x10 y225 w410 h20 center BackgroundTrans,Start :: NumPad1 <---> Stop :: Esc <---> Exit :: Ctrl+Esc
	Gui,2:Show,x10 y40 w430 h250
}
Defall:
	if(!pButton[A_GuiControl].Button_Press()) 
		return
	GuiControl,2:,Commands,*1*1*1*10*10*Left*%M_Delay%*%Key_Delay%*%Delay%*
	return
DefallM:
	if(!pButton[A_GuiControl].Button_Press()) 
		return
	GuiControl,2:,Commands,*1*0*1*10*10*Left*%M_Delay%*%Key_Delay%*%Delay%*
	return
DefallT:
	if(!pButton[A_GuiControl].Button_Press()) 
		return
	GuiControl,2:,Commands,*1*0*0*10*10*Left*%M_Delay%*%Key_Delay%*%Delay%*
	return	
Tips:
	if(!pButton[A_GuiControl].Button_Press()) 
		return
	Gui,Tips:Destroy
	Gui,Tips:+AlwaysOnTop +Owner1 -DPIScale
	Gui,Tips:Color,7200ff
	
	Gui,Tips:Font,cBlack s10 bold Q5,Segoe UI

	Gui,Tips:Add,Edit,x10 y10 w1000 -VScroll ReadOnly,% Tips_Text
	Gui,Tips:Show,x0 y0 NA,Tips
	return	
Start_Search:
	if(!pButton[A_GuiControl].Button_Press()) 
		return
	Gui,2:Submit,NoHide
	Run_Search()
	return
Numpad1::
Run_Search(){
	Stop:=0
	Active:=1		
	While(!Stop){
			PixelSearch,x,y,X_Pos,Y_Pos,cx2,cy2,Color_Edit,Variation,Fast|RGB
		if(ErrorLevel=0&&pRadio[1].State=1){
			stringleft,tep,Commands,1
			if(tep="*"){
				CMove:="",CTimes:="",XOff:="",YOff:="",TypeC:="Left",RTimes:=1,Send_Stuff:=""
				Loop, Parse, Commands,*
					{
						(A_Index=2)?(RTimes:=A_LoopField)
						:(A_Index=3)?(CMove:=A_LoopField)
						:(A_Index=4)?(CTimes:=A_LoopField)
						:(A_Index=5)?(XOff:=A_LoopField)
						:(A_Index=6)?(YOff:=A_LoopField)
						:(A_Index=7)?(TypeC:=A_LoopField)
						:(A_Index=8)?(M_Delay:=A_LoopField)
						:(A_Index=9)?(Key_Delay:=A_LoopField)
						:(A_Index=10)?(Delay:=A_LoopField)
						:(A_Index=11)?(Send_Stuff:=A_LoopField)
					}
					SetKeyDelay,Key_Delay ,10
					SetMouseDelay,M_Delay
				ClickingFun(CMove,CTimes,XOff,YOff,TypeC,x,y)
				if(Send_Stuff){
					Send,% Send_Stuff
				}
				if(RTimes!=1)
					gosub,Stop_P2
				
			}else if(tep!="*"){
				Send,%Commands%
			}
			Sleep, Delay
		}
		else if(ErrorLevel=1&&pRadio[2].State=1){
			stringleft,tep,Commands,1
			if(tep="*"){
				CMove:="",CTimes:="",XOff:="",YOff:="",TypeC:="Left",RTimes:=1,Send_Stuff:=""
				Loop, Parse, Commands,*
					{
						(A_Index=2)?(RTimes:=A_LoopField)
						:(A_Index=3)?(CMove:=A_LoopField)
						:(A_Index=4)?(CTimes:=A_LoopField)
						:(A_Index=5)?(XOff:=A_LoopField)
						:(A_Index=6)?(YOff:=A_LoopField)
						:(A_Index=7)?(TypeC:=A_LoopField)
						:(A_Index=8)?(M_Delay:=A_LoopField)
						:(A_Index=9)?(Key_Delay:=A_LoopField)
						:(A_Index=10)?(Delay:=A_LoopField)
						:(A_Index=11)?(Send_Stuff:=A_LoopField)
					}
					SetKeyDelay,Key_Delay ,10
					SetMouseDelay,M_Delay
				ClickingFun(CMove,CTimes,XOff,YOff,TypeC,x,y)
				if(Send_Stuff){
					Send,% Send_Stuff
				if(RTimes!=1)
					gosub,Stop_P2
				}
			}else if(tep!="*"){
				Send,%Commands%
			}
			Sleep, Delay
		}
	}
	Tooltip,
}
return


ClickingFun(CMove,CTimes,XOff,YOff,TypeC,x,y){
	if((CTimes=0&&CMove=0)||(CTimes=""&&CMove="")){
		return
	}
	x3:=x+XOff,y3:=y+YOff
	MouseMove, x3 , y3
	if(CMove=1){
		if(CTimes>1){
			Loop,% CTimes
			Click, %TypeC%,
		}
		else
			Click, %TypeC%,
	}	
}
#if (Active)
*Esc::
	gosub,Stop_P2
	return
#If
Stop_Search:
	if(!pButton[A_GuiControl].Button_Press()) 
		return
Stop_P2:	
	Stop:=1
	Active:=0
	return
Reload:
	if(!pButton[A_GuiControl].Button_Press()) 
		return
	Reload
	return
Set_Truth:
	Stop:=1
	Loop 2
		{
			if(pRadio[A_Index].Name=A_GuiControl){
				Swap_Radio_State(A_GuiControl)
			}
		}
	return
AHK_Send_Page:
	Stop:=1
	if(!pButton[A_GuiControl].Button_Press()) 
		return
	Try
		run,https://autohotkey.com/docs/commands/Send.htm
	return
Submit_All:
	Stop:=1
	Gui,2:Submit,NoHide
	GuiControl,2:+c%Color_Edit%,Selected_Color
	return
Tag:
	Stop:=1
	if(!pButton[A_GuiControl].Button_Press()) 
		return
	Try
		Run,https://www.youtube.com/user/CivReborn
	return
Win_Min:
	Gui,1:Minimize
	return	
Win_Move:
	PostMessage,0xA1,2
	while(Getkeystate("LButton"))
		SetTimer,Watch_Hover,off
	SetTimer,Watch_Hover,10
	return	
Get_Color:
	Stop:=1
	if(!pButton[A_GuiControl].Button_Press()) 
		return
	While(!GetKeyState("ctrl")){
		MouseGetPos,tx,ty
		PixelGetColor,Selected_Color,tx,ty,RGB
		ToolTip,Press ""ctrl"" to set colour
		GuiControl,2:+c%Selected_Color%,Selected_Color
		GuiControl,2:,Color_Edit,%Selected_Color%
	}
	tooltip,
	return	
Set_Position:
	Stop:=1
	if(!pButton[A_GuiControl].Button_Press()) 
		return
	SPOS()
	return	
SPOS(){
	global
	if(!pToken)
		pToken:=GDip_Startup()
	Gui,3:-Caption -DPIScale +LastFound +E0x80000 +ToolWindow +AlwaysOnTop
	Gui,3:Show,x0 y0 w%A_ScreenWidth% h%A_ScreenHeight% NA
	hwnd1:=WinExist(),hbm := CreateDIBSection(A_ScreenWidth,A_ScreenHeight),hdc := CreateCompatibleDC(),obm := SelectObject(hdc,hbm)
	G := Gdip_GraphicsFromHDC(hdc),Gdip_SetSmoothingMode(G,4),UpdateLayeredWindow(hwnd1, hdc, 0, 0,A_ScreenWidth,A_ScreenHeight)
	Br1:=New_Brush("ff0066","ff"),Br2:=New_Brush("12e854","55"),Br3:=New_Brush("de0d0a","aa")
	UpdateLayeredWindow(hwnd1, hdc),Pos_Setting_Active:=1,TL:=1
	SetTimer,Draw_Cross,10
}
Draw_Cross:
	Gdip_GraphicsClear(G)
	if(TL=1){
		MouseGetPos,cx,cy
		Fill_Box(G,Br1,0,cy,A_ScreenWidth,1),Fill_Box(G,Br1,cx,0,1,A_ScreenHeight)
		GuiControl,2:,X_Pos,% cx
		GuiControl,2:,Y_Pos,% cy
	}
	else if(TL=2){
		MouseGetPos,cx2,cy2
		if(cx2-cx>=0&&cy2-cy>=0){
			OB:=0
			Fill_Box(G,Br1,0,cy2,A_ScreenWidth,1),Fill_Box(G,Br1,cx2,0,1,A_ScreenHeight),Fill_Box(G,Br1,0,cy,A_ScreenWidth,1)
			Fill_Box(G,Br1,cx,0,1,A_ScreenHeight),Fill_Box(G,Br2,cx,cy,cx2-cx,cy2-cy)
			GuiControl,2:,W_Pos,% cx2 - cx
			GuiControl,2:,H_Pos,% cy2 - cy
		}
		else if(cx2-cx>=0&&cy2-cy<0){
			OB:=1
			Fill_Box(G,Br1,0,cy2,A_ScreenWidth,1),Fill_Box(G,Br1,cx2,0,1,A_ScreenHeight),Fill_Box(G,Br1,0,cy,A_ScreenWidth,1)
			Fill_Box(G,Br1,cx,0,1,A_ScreenHeight),Fill_Box(G,Br3,cx,cy2,cx2-cx,cy-cy2)
			GuiControl,2:,W_Pos,% (cx2 - cx)
			GuiControl,2:,H_Pos,% (cy2 - cy)*-1
		}
		else if(cx2-cx<0&&cy2-cy>=0){
			OB:=1
			Fill_Box(G,Br1,0,cy2,A_ScreenWidth,1),Fill_Box(G,Br1,cx2,0,1,A_ScreenHeight),Fill_Box(G,Br1,0,cy,A_ScreenWidth,1)
			Fill_Box(G,Br1,cx,0,1,A_ScreenHeight),Fill_Box(G,Br3,cx2,cy,cx-cx2,cy2-cy)
			GuiControl,2:,W_Pos,% (cx2 - cx)*-1
			GuiControl,2:,H_Pos,% (cy2 - cy)
		}
		else if(cx2-cx<0&&cy2-cy<0){
			OB:=1
			Fill_Box(G,Br1,0,cy2,A_ScreenWidth,1),Fill_Box(G,Br1,cx2,0,1,A_ScreenHeight),Fill_Box(G,Br1,0,cy,A_ScreenWidth,1)
			Fill_Box(G,Br1,cx,0,1,A_ScreenHeight),Fill_Box(G,Br3,cx2,cy2,cx-cx2,cy-cy2)
			GuiControl,2:,W_Pos,% (cx2 - cx)*-1
			GuiControl,2:,H_Pos,% (cy2 - cy)*-1
		}
	}
	UpdateLayeredWindow(hwnd1, hdc)	
	return


#If (Pos_Setting_Active=1)
*Lbutton::
	if(TL=1)
		TL:=2
	else if(TL=2&&OB=0){
		Gui,3:Destroy
		Pos_Setting_Active:=0,GDip_Shutdown(pToken),pToken:=""
		SetTimer,Draw_Cross,Off
	}
	return
#If

pButton_StartUp(){
	SetTimer,Watch_Hover,10
}
Watch_Hover(){
	global
	if(Press_active=0){
		if(Hover_On=0){
			MouseGetPos,,,,ctrl,2
			loop,% pButton.Length()	{
				GuiControlGet,cName,% pButton[A_Index].Window_Name ":Name",% ctrl
				cut:=Strlen(cName)
				StringLeft,bName,cName,cut-2
				if(bname=pButton[A_Index].Button_Name){
					pButton[A_Index].Button_Hover_On(),Hover_On:=1,Active_Button:=bname,win:=pButton[A_Index].Window_Name
					return
				}
		}
		}else if(Hover_On=1){
			MouseGetPos,,,,ctrl,2
			GuiControlGet,cName,%win%:Name,% ctrl
			cut:=Strlen(cName)
			StringLeft,nBName,cName,cut-2
			if(NbName!=Active_Button){
				pButton[Active_Button].Button_Hover_Off()
				Hover_On:=0,Active_Button:=""
			}
		}
	}
}

Class Progress_Button	{
		__New(Window_Name,Button_Name,Label,x,y,w,h,BC,TRC,TC1,TC2,TC3,Button_Text,Text_Offset:=0)
			{
				This.Text_Offset:=Text_Offset
				This.Window_Name:=Window_Name
				This.Button_Name:=Button_Name
				This.Label:=Label
				This.Button_ID1:=Button_Name "_1"
				This.Button_ID2:=Button_Name "_2"
				This.Button_ID3:=Button_Name "_3"
				This.Button_ID4:=Button_Name "_4"
				This.Button_Text:=Button_Text
				This.X:=x
				This.Y:=y
				This.W:=w
				This.H:=h
				This.Bottom_Color:=BC
				This.Trim_Color:=TRC
				This.Top_Color_1:=TC1
				This.Top_Color_2:=TC2
				This.Top_Color_3:=TC3
				This.Add_Button()
			}
		Add_Button()
			{
				global
				Gui,% This.Window_Name ":Add",Text,% "x" This.X " y" This.Y " w" This.W " h" This.H " v" This.Button_Name " g" This.Label
				Gui,% This.Window_Name ":Add",Progress,% "x" This.X " y" This.Y " w" This.W " h" This.H " Background" This.Bottom_Color " v" This.Button_ID1
				Gui,% This.Window_Name ":Add",Progress,% "x" This.X " y" This.Y " w" This.W-1 " h" This.H-1 " Background" This.Trim_Color " v" This.Button_ID2
				Gui,% This.Window_Name ":Add",Progress,% "x" This.X+1 " y" This.Y+1 " w" This.W-2 " h" This.H-2 " Background" This.Top_Color_1 " v" This.Button_ID3
				Gui,% This.Window_Name ":Add",Text,% "x" This.X+1 " y" This.Y+This.Text_Offset " w" This.W-2 " r1 Center BackgroundTrans v" This.Button_ID4,% This.Button_Text
			}
		Button_Press()
			{
				global
				Press_Active:=1
				GuiControl,% This.Window_Name ":Move",% This.Button_ID4,% "x" This.X+1 " y" This.Y+1+This.Text_Offset
				sleep,-1
				GuiControl,% This.Window_Name ":Hide",This.Button_ID2
				GuiControl,% This.Window_Name ":+Background" This.Top_Color_3,% This.Button_ID3
				GuiControl,% This.Window_Name ":+Redraw",% This.Button_ID1
				GuiControl,% This.Window_Name ":+Redraw",% This.Button_ID3
				GuiControl,% This.Window_Name ":+Redraw",% This.Button_ID4
				While(GetKeyState("LButton"))
					Sleep, 10
				MouseGetPos,,,,ctrl,2
				GuiControlGet,cName,% win ":Name",% ctrl
				cut:=Strlen(cName)
				StringLeft,bName,cName,cut-2
				if(bname=This.Button_Name)
					{
						GuiControl,% This.Window_Name ":Show",This.Button_ID2
						GuiControl,% This.Window_Name ":+Background" This.Top_Color_1,% This.Button_ID3
						GuiControl,% This.Window_Name ":+Redraw",% This.Button_ID1
						GuiControl,% This.Window_Name ":+Redraw",% This.Button_ID2
						GuiControl,% This.Window_Name ":+Redraw",% This.Button_ID3
						GuiControl,% This.Window_Name ":Move",% This.Button_ID4,% "x" This.X " y" This.Y+This.Text_Offset
						GuiControl,% This.Window_Name ":+Redraw",% This.Button_ID4
						%bName%.Button_Hover_On()
						Hover_On:=0
						Active_Button:=bname
						Press_Active:=0
						sleep,10
						return true
					}
				GuiControl,% This.Window_Name ":Show",This.Button_ID2
				GuiControl,% This.Window_Name ":Move",% This.Button_ID4,% "x" This.X " y" This.Y+This.Text_Offset
				GuiControl,% This.Window_Name ":+Background" This.Top_Color_1,% This.Button_ID3
				GuiControl,% This.Window_Name ":+Redraw",% This.Button_ID1
				GuiControl,% This.Window_Name ":+Redraw",% This.Button_ID2
				GuiControl,% This.Window_Name ":+Redraw",% This.Button_ID3
				GuiControl,% This.Window_Name ":+Redraw",% This.Button_ID4
				Hover_On:=0
				Press_Active:=0
				sleep,10
				return False
			}
		Button_Hover_On(){
			global
			GuiControl,% This.Window_Name ":+Background" This.Top_Color_2,% This.Button_ID3
			GuiControl,% This.Window_Name ":+Redraw",% This.Button_ID4
		}
		Button_Hover_Off()
			{
				global
				GuiControl,% This.Window_Name ":+Background" This.Top_Color_1,% This.Button_ID3
				GuiControl,% This.Window_Name ":+Redraw",% This.Button_ID4
			}
	}	
Get_Name(Name){
	global
	Loop, % pCheckBox.Length()
		if(Name=pCheckBox[A_Index].Name||Name=pCheckBox[A_Index].Checkbox_ID4){
			pCheckBox[A_Index].UpDate_CheckBox()
			break
		}
}
Class Progress_CheckBox	{
	__New(Window_Name,Checkbox_Name,Label,Start_State,x,y,w,h,Text_X_Offset,Text_Y_Offset,Outer_Color,Inner_Color,Check_On_Colour,Check_Off_Colour,Check_Box_Text,Outer_Thickness:=1,Inner_Thickness:=1){
		This.X:=x,This.Y:=y,This.W:=w,This.H:=h
		This.Text_X_Offset:=Text_X_Offset,This.Text_Y_Offset:=Text_Y_Offset
		This.Outer_Thickness:=Outer_Thickness,This.Inner_Thickness:=Inner_Thickness
		This.Outer_Trim_Colour:=Outer_Color,This.Inner_Trim_Colour:=Inner_Color
		This.Check_On_Colour:=Check_On_Colour,This.Check_Off_Colour:=Check_Off_Colour
		This.Name:=Checkbox_Name,This.Checkbox_ID1:=This.Name "_1",This.Checkbox_ID2:=This.Name "_2",This.Checkbox_ID3:=This.Name "_3",This.Checkbox_ID4:=This.Name "_4"
		This.Window_Name:=Window_Name,This.Label:=Label
		This.Outer_Trim_Thickness:=Outer_Thickness,This.Inner_Trim_Thickness:=Inner_Thickness
		This.Is_On:=Start_State,This.Text:=Check_Box_Text
		This.Add_CheckBox()
	}
	Add_CheckBox(){
		global
		Gui,% This.Window_Name ":Add",Text,% "x" This.X " y" This.Y " w" This.W " h" This.H " v" This.Name " g" This.Label
		Gui,% This.Window_Name ":Add",Progress,% "x" This.X " y" This.Y " w" This.W " h" This.H " BackGround" This.Outer_Trim_Colour " v" This.Checkbox_ID1 
		Gui,% This.Window_Name ":Add",Progress,% "x" This.X+This.Outer_Thickness " y" This.Y+This.Outer_Thickness " w" This.W-(2*This.Outer_Thickness) " h" This.H-(2*This.Outer_Thickness) " BackGround" This.Inner_Trim_Colour " v" This.Checkbox_ID2 
		(This.Is_On=1)?(col:=This.Check_On_Colour):(col:=This.Check_Off_Colour)
		Gui,% This.Window_Name ":Add",Progress,% "x" This.X+This.Outer_Thickness+This.Inner_Thickness " y" This.Y+This.Outer_Thickness+This.Inner_Thickness " w" This.W - ((2*This.Outer_Thickness)+(2*This.Inner_Thickness)) " h" This.H - ((2*This.Outer_Thickness)+(2*This.Inner_Thickness)) " BackGround" col " v" This.Checkbox_ID3 
		Gui,% This.Window_Name ":Add",Text,% "x" This.X+This.W+This.Text_X_Offset " y" This.Y+This.Text_Y_Offset " Backgroundtrans v" This.Checkbox_ID4 " g" This.Label,% This.Text
	}
	UpDate_CheckBox(){
		if(This.Is_On:=!This.Is_On){
			GuiControl,% This.Window_Name ":+Background" This.Check_On_Colour,% This.Checkbox_ID3 
			GuiControl,% This.Window_Name ":+Redraw",% This.Checkbox_ID4
		}else	{
			GuiControl,% This.Window_Name ":+Background" This.Check_Off_Colour,% This.Checkbox_ID3
			GuiControl,% This.Window_Name ":+Redraw",% This.Checkbox_ID4
		}
	}
}
Swap_Radio_State(Control){
	Loop, % pRadio.Length()
		if((Control=pRadio[A_Index].Name||Control=pRadio[A_Index].Radio_ID4)&&pRadio[A_Index].State!=1){
			pRadio[A_Index].Update_Radio()
			break
		}
}
class Progress_Radio	{
	__New(Window_Name,Radio_Name,Label,Start_State,Group_Name,x,y,w,h,Text_X_Offset,Text_Y_Offset,Outer_Color,Inner_Color,Radio_On_Colour,Radio_Off_Colour,Radio_Text,Outer_Thickness:=1,Inner_Thickness:=1){
		This.X:=x,This.Y:=y,This.W:=w,This.H:=h,This.Group:=Group_Name,This.Text_X_Offset:=Text_X_Offset,This.Text_Y_Offset:=Text_Y_Offset
		This.Outer_Thickness:=Outer_Thickness,This.Inner_Thickness:=Inner_Thickness,This.Outer_Trim_Colour:=Outer_Color,This.Inner_Trim_Colour:=Inner_Color
		This.Radio_On_Colour:=Radio_On_Colour,This.Radio_Off_Colour:=Radio_Off_Colour,This.Name:=Radio_Name,This.Radio_ID1:=This.Name "_1",This.Radio_ID2:=This.Name "_2",This.Radio_ID3:=This.Name "_3"
		This.Radio_ID4:=This.Name "_4",This.Window_Name:=Window_Name,This.Label:=Label,This.Outer_Trim_Thickness:=Outer_Thickness,This.Inner_Trim_Thickness:=Inner_Thickness
		This.State:=Start_State,This.Text:=Radio_Text
		This.Add_Radio()
	}
	Add_Radio(){
		global
		Gui,% This.Window_Name ":Add",Text,% "x" This.X " y" This.Y " w" This.W " h" This.H " v" This.Name " g" This.Label
		Gui,% This.Window_Name ":Add",Progress,% "x" This.X " y" This.Y " w" This.W " h" This.H " BackGround" This.Outer_Trim_Colour " v" This.Radio_ID1 
		Gui,% This.Window_Name ":Add",Progress,% "x" This.X+This.Outer_Thickness " y" This.Y+This.Outer_Thickness " w" This.W-(2*This.Outer_Thickness) " h" This.H-(2*This.Outer_Thickness) " BackGround" This.Inner_Trim_Colour " v" This.Radio_ID2 
		(This.State=1)?(col:=This.Radio_On_Colour):(col:=This.Radio_Off_Colour)
		Gui,% This.Window_Name ":Add",Progress,% "x" This.X+This.Outer_Thickness+This.Inner_Thickness " y" This.Y+This.Outer_Thickness+This.Inner_Thickness " w" This.W - ((2*This.Outer_Thickness)+(2*This.Inner_Thickness)) " h" This.H - ((2*This.Outer_Thickness)+(2*This.Inner_Thickness)) " BackGround" col " v" This.Radio_ID3 
		Gui,% This.Window_Name ":Add",Text,% "x" This.X+This.W+This.Text_X_Offset " y" This.Y+This.Text_Y_Offset " Backgroundtrans v" This.Radio_ID4 " g" This.Label,% This.Text
	}
	Update_Radio(){
		Loop,% pRadio.Length()	{
			if(pRadio[A_Index].State=1&&pRadio[A_Index].Group=This.Group){
				GuiControl,% pRadio[A_Index].Window_Name ":+Background" pRadio[A_Index].Radio_Off_Colour,% pRadio[A_Index].Radio_ID3 
				GuiControl,% pRadio[A_Index].Window_Name ":+Redraw",% pRadio[A_Index].Radio_ID4
				pRadio[A_Index].State:=0
			}
		}
		GuiControl,% This.Window_Name ":+Background" This.Radio_On_Colour,% This.Radio_ID3
		GuiControl,% This.Window_Name ":+Redraw",% This.Radio_ID4
		This.State:=1
	}
}
Gdip_DeleteBrush(pBrush)
{
   return DllCall("gdiplus\GdipDeleteBrush", A_PtrSize ? "UPtr" : "UInt", pBrush)
}
Gdip_DeletePen(pPen)
{
   return DllCall("gdiplus\GdipDeletePen", A_PtrSize ? "UPtr" : "UInt", pPen)
}
Gdip_DisposeImage(pBitmap)
{
   return DllCall("gdiplus\GdipDisposeImage", A_PtrSize ? "UPtr" : "UInt", pBitmap)
}
Layered_Window_ShutDown(This)
	{
		SelectObject(This.hdc,This.obm)
		DeleteObject(This.hbm)
		DeleteDC(This.hdc)
		gdip_deleteGraphics(This.g)
		Gdip_Shutdown(This.Token)
	}
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)
}
DeleteObject(hObject)
{
   return DllCall("DeleteObject", A_PtrSize ? "UPtr" : "UInt", hObject)
}
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_GraphicsFromImage(pBitmap)
{
	DllCall("gdiplus\GdipGetImageGraphicsContext", A_PtrSize ? "UPtr" : "UInt", pBitmap, A_PtrSize ? "UPtr*" : "UInt*", pGraphics)
	return pGraphics
}
Gdip_SetSmoothingMode(pGraphics, SmoothingMode)
{
   return DllCall("gdiplus\GdipSetSmoothingMode", A_PtrSize ? "UPtr" : "UInt", pGraphics, "int", SmoothingMode)
}
New_Brush(colour:="000000",Alpha:="FF")
	{
		;~ static Hellbent_Brush:=[]
		new_colour := "0x" Alpha colour 
		;~ Hellbent_Brush[Hellbent_Brush.Length()+1]:=Gdip_BrushCreateSolid(new_colour)
		return Gdip_BrushCreateSolid(new_colour)
	}
Fill_Box(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_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_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_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_DeleteGraphics(pGraphics)
{
   return DllCall("gdiplus\GdipDeleteGraphics", A_PtrSize ? "UPtr" : "UInt", pGraphics)
}
Layered_Window_SetUp(Smoothing,Window_X,Window_Y,Window_W,Window_H,Window_Name:=1,Window_Options:="")
	{
		Layered:={}
		Layered.W:=Window_W
		Layered.H:=Window_H
		Layered.X:=Window_X
		Layered.Y:=Window_Y
		Layered.Name:=Window_Name
		Layered.Options:=Window_Options
		Layered.Token:=Gdip_Startup()
		Create_Layered_GUI(Layered)
		Layered.hwnd:=winExist()
		Layered.hbm := CreateDIBSection(Window_W,Window_H)
		Layered.hdc := CreateCompatibleDC()
		Layered.obm := SelectObject(Layered.hdc,Layered.hbm)
		Layered.G := Gdip_GraphicsFromHDC(Layered.hdc)
		Gdip_SetSmoothingMode(Layered.G,Smoothing)
		return Layered
	}
Gdip_GraphicsClear(pGraphics, ARGB=0x00ffffff)
{
    return DllCall("gdiplus\GdipGraphicsClear", A_PtrSize ? "UPtr" : "UInt", pGraphics, "int", ARGB)
}
New_Pen(colour:="000000",Alpha:="FF",Width:= 5)
	{
		;~ static Hellbent_Pen:=[]
		new_colour := "0x" Alpha colour 
		;~ Hellbent_Pen[Hellbent_Pen.Length()+1]:=Gdip_CreatePen(New_Colour,Width)
		return Gdip_CreatePen(New_Colour,Width)
	}
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_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_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_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)
}
SelectObject(hdc, hgdiobj)
{
	Ptr := A_PtrSize ? "UPtr" : "UInt"
	
	return DllCall("SelectObject", Ptr, hdc, Ptr, hgdiobj)
}
DeleteDC(hdc)
{
   return DllCall("DeleteDC", A_PtrSize ? "UPtr" : "UInt", hdc)
}
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_BrushCreateSolid(ARGB=0xff000000)
{
	DllCall("gdiplus\GdipCreateSolidFill", "UInt", ARGB, 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_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_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_StringFormatCreate(Format=0, Lang=0)
{
   DllCall("gdiplus\GdipCreateStringFormat", "int", Format, "int", Lang, A_PtrSize ? "UPtr*" : "UInt*", hFormat)
   return hFormat
}
Gdip_SetStringFormatAlign(hFormat, Align)
{
   return DllCall("gdiplus\GdipSetStringFormatAlign", A_PtrSize ? "UPtr" : "UInt", hFormat, "int", Align)
}
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
}
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_DeleteStringFormat(hFormat)
{
   return DllCall("gdiplus\GdipDeleteStringFormat", A_PtrSize ? "UPtr" : "UInt", hFormat)
}
Gdip_DeleteFont(hFont)
{
   return DllCall("gdiplus\GdipDeleteFont", A_PtrSize ? "UPtr" : "UInt", hFont)
}
Gdip_DeleteFontFamily(hFamily)
{
   return DllCall("gdiplus\GdipDeleteFontFamily", A_PtrSize ? "UPtr" : "UInt", hFamily)
}
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_DisposeImageAttributes(ImageAttr)
{
	return DllCall("gdiplus\GdipDisposeImageAttributes", A_PtrSize ? "UPtr" : "UInt", ImageAttr)
}
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
}
Create_Layered_GUI(Layered)
	{
		Gui,% Layered.Name ": +E0x80000 +LastFound " Layered.Options 
		Gui,% Layered.Name ":Show",% "x" Layered.X " y" Layered.Y " w" Layered.W " h" Layered.H " NA"
	}
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
}
CreateCompatibleDC(hdc=0)
{
   return DllCall("CreateCompatibleDC", A_PtrSize ? "UPtr" : "UInt", hdc)
}
Gdip_GraphicsFromHDC(hdc)
{
    DllCall("gdiplus\GdipCreateFromHDC", A_PtrSize ? "UPtr" : "UInt", hdc, A_PtrSize ? "UPtr*" : "UInt*", pGraphics)
    return pGraphics
}
Gdip_CreatePen(ARGB, w)
{
   DllCall("gdiplus\GdipCreatePen1", "UInt", ARGB, "float", w, "int", 2, A_PtrSize ? "UPtr*" : "UInt*", pPen)
   return pPen
}
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_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_SetClipRegion(pGraphics, Region, CombineMode=0)
{
	Ptr := A_PtrSize ? "UPtr" : "UInt"
	
	return DllCall("gdiplus\GdipSetClipRegion", Ptr, pGraphics, Ptr, Region, "int", CombineMode)
}
Gdip_DeleteRegion(Region)
{
	return DllCall("gdiplus\GdipDeleteRegion", A_PtrSize ? "UPtr" : "UInt", Region)
}
Gdip_ResetClip(pGraphics)
{
   return DllCall("gdiplus\GdipResetClip", A_PtrSize ? "UPtr" : "UInt", pGraphics)
}
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)
}
GetDC(hwnd=0)
{
	return DllCall("GetDC", A_PtrSize ? "UPtr" : "UInt", hwnd)
}
ReleaseDC(hdc, hwnd=0)
{
	Ptr := A_PtrSize ? "UPtr" : "UInt"
	
	return DllCall("ReleaseDC", Ptr, hwnd, Ptr, hdc)
}
Gdip_CreateRegion()
{
	DllCall("gdiplus\GdipCreateRegion", "UInt*", Region)
	return Region
}
	
;Hotkeys
;------------------------------------------------------------------------
#If (Stop=0)	
*^ESC::ExitApp
#if
User avatar
Scr1pter
Posts: 1271
Joined: 06 Aug 2017, 08:21
Location: Germany

Re: [Gdip] How to draw lines and retrieve pixel length?

20 Jan 2019, 16:10

Hi friends,

First off: Thank you very much for all your help!

I checked your posts and links.
After reading I realized that the compass script, which was mentioned by FanaticGuru, contained 1 single line which solves the painting problem.
(The problem I mentioned in the last GIF)
DllCall("gdiplus.dll\GdipGraphicsClear", "Ptr", G, "UInt", 0x00FFFFFF)
It seems that this line deletes old/invalid graphics so that you'll always have 1 line which is up to date.

So I tried to rework my script before going with a completely other script.
Usually I have no problems using other scripts, but the problem is that there are many many lines which I don't understand.
Additionally, they have features I don't need or features are missing.

At the current state, both problems which I had before are solved now!
- the lines are absolutely clear (no old pixels)
- the ahk bug is also solved by reloading the script

That's the (almost) final code, and it's actually pretty small:

Code: Select all

;Draw lines
^+!F8:: ; Ctrl+Shift+Alt+F8
ctrlShiftAltF8Counter++ ; Increment each time combination was pressed
if ctrlShiftAltF8Counter = 4 ; If combination was pressed 4 times:
{
  reload ; Reload script to prevent AHK crash (bug?)
}
if paintMode ; If paint mode is already active:
{
  Gui_Anweisungen(0, "", "", "", "") ; Fade-Out instruction GUI
  paintMode := !paintMode ; Turn off paint mode (0)
  SelectObject(hdc, obm) ; Select the object back into the hdc
  DeleteObject(hbm) ; Now the bitmap may be deleted
  Gdip_DeletePen(pPen) ; Delete the pen as it is no longer needed and wastes memory 
  DeleteDC(hdc) ; Also the device context related to the bitmap may be deleted
  Gdip_DeleteGraphics(G) ; The graphics may now be deleted
  Gdip_Shutdown(pToken) ; Close Gdip instance
  Loop, %i% ; Repeat as many times as number of guis 
  {
    Gui, %A_Index%: Destroy ; Destroy all guis which have been created recently
  }
  i = 0 ; Reset incrementer
  pixel = ; Reset pixel values
}
else ; If it's not active:
{
  paintMode := !paintMode ; Turn on paintMode (1)
  Gui_Anweisungen(1, "Paint mode", "Instructions:", "Draw a line!", "Press Ctrl+Shift+Alt+F8 to exit") ; Fade-in instruction GUI
  pToken := Gdip_Startup() ; Start gdip instance
}
return

#if paintMode ; If paint mode is active:
#include Gdip.ahk ; Include Gdip library

lbutton::
i++ ; incrementer for each mouse click
CoordMode, Mouse, Screen ; Absolute position
MouseGetPos, xStart, yStart ; Retrieve mouse position (pressed/down)
Width := A_ScreenWidth, Height := A_ScreenHeight ; Set the width and height we want as our drawing area, to draw everything in. This will be the dimensions of our bitmap
Gui, %i%: -Caption +E0x80000 +LastFound +OwnDialogs +Owner +AlwaysOnTop ; Create a layered window (+E0x80000: must be used for UpdateLayeredWindow to work!) that is always on top (+AlwaysOnTop), no taskbar entry or caption
Gui, %i%: Show, NA ; Show the window which contains the freshly drawn line (without activating it)
hwnd := WinExist() ; Get a handle to this window we have created in order to update it later
hbm  := CreateDIBSection(Width, Height) ; Create a gdi bitmap with width and height 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
Gdip_SetSmoothingMode(G, 4) ; Set the smoothing mode to antialias = 4 to make shapes appear smother (only used for vector drawing and filling)
pPen := Gdip_CreatePen(0xffff0000, 3) ; Create a fully opaque red pen (ARGB = Transparency, red, green, blue) of width 3 (the thickness the pen will draw at) to draw a line
while GetKeyState("lbutton", "P") ; While left mouse buttons is being held:
{ 
  MouseGetPos, xCurrent, yCurrent ; Retrieve current mouse position
  Gdip_DrawLine(G, pPen, xStart, yStart, xCurrent, yCurrent) ; Gdip_DrawLine(pGraphics, pPen, x1, y1, x2, y2), which have been set by using left mouse button 
  UpdateLayeredWindow(hwnd, hdc, 0, 0, Width, Height) ; So this will position our gui at (0,0) with the Width and Height specified earlier 
  DllCall("gdiplus.dll\GdipGraphicsClear", "Ptr", G, "UInt", 0x00FFFFFF) ; Delete old lines (to have just 1 updated line all the time)
}
differenceX := xCurrent - xStart ; Calculate difference between both x points
differenceX := StrReplace(differenceX, "-") ; If it's a negative number, convert it to a positive one.
differenceY := yCurrent - yStart ; Calculate difference between both y points
differenceY := StrReplace(differenceY, "-") ; If it's a negative number, convert it to a positive one.
difference  := differenceX + differenceY ; Calculate pixel length
pixel .= difference . "`, " ; Add new pixel value to old one, separate them by , -> Doesn't work, old pixel value gets overwritten
Gui_Text_Aendern("Pixel:", "schritte", pixel, "anweisungen") ; Update instruction GUI with new pixels
return
#if ; Close #if-block
Regarding the ahk bug (why I think it's a bug):
If I only use the instruction GUI without anything, I can open and close it as often as I want.
The same for the painting functionality (without using the instruction GUI), I can also activate it endlessly.
Both together work only 2 times in a row!
1x Ctrl+Shift+Alt+F8 = ON
2x Ctrl+Shift+Alt+F8 = OFF
3x Ctrl+Shift+Alt+F8 = ON
4x Ctrl+Shift+Alt+F8 = OFF
5x Ctrl+Shift+Alt+F8 = CRASH
This I why I force a reload.

Anyway, that's how it looks:
Image

I wish I could mark all your posts as "best answer", but I'll go with FanaticGuru's one, because the link actually contained the magic codeline.

Thanks to both of you!!

Cheers!
Please use [code][/code] when posting code!
Keyboard: Logitech G PRO - Mouse: Logitech G502 LS - OS: Windows 10 Pro 64 Bit - AHK version: 1.1.33.09
User avatar
Hellbent
Posts: 2102
Joined: 23 Sep 2017, 13:34

Re: [Gdip] How to draw lines and retrieve pixel length?

20 Jan 2019, 17:21

Scr1pter wrote:
20 Jan 2019, 16:10
but I'll go with FanaticGuru's one, because the link actually contained the magic codeline.

Cough :trollface:

Hellbent wrote:
15 Jan 2019, 18:57

Code: Select all

DrawStuff:
	Gdip_GraphicsClear(GdipOBJ.G)
	MouseGetPos,ex,ey
	Gdip_DrawLine(GdipOBJ.G, myPen, sx, sy, ex, ey)
	UpdateLayeredWindow(GdipOBJ.hwnd, GdipOBJ.hdc)
	if(GETKEYSTATE("Shift")){
		active_Draw:=0
		SetTimer,DrawStuff,off
		tooltip,% "The lenght is " abs(Sqrt(((sx-ex)**2) + ((sy-ey)**2)))
		Gdip_DeletePen(myPen)
	}
	return
All kidding aside, I'm glad you were able to get it to work the way you wanted it to. Working with gdip can be really fun, but also a real headache.

Return to “Ask for Help (v1)”

Who is online

Users browsing this forum: Google [Bot] and 118 guests