Need help with a drag+drop overlay class

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
doubledave22
Posts: 343
Joined: 08 Jun 2019, 17:36

Need help with a drag+drop overlay class

Post by doubledave22 » 15 Jan 2022, 17:31

using the example from this thread: viewtopic.php?t=6966

Try this script on a notepad window. You should be able to drag the text to the edges and everything works fine enough how I want. The issue is that WM_MOUSELEAVE() and WM_MOUSEHOVER() are never called. What I want is the background to be visible with transparency when hovered and then reset when hovered off.

Code: Select all

#SingleInstance force
return

^+d::
newwin := Winexist("A")
wingetpos, windowx, windowy, , , A
Test1 := new TestClass(newwin,"Test1", windowx+100, windowy+100)
return

class TestClass {
	static DerivedObjectsCount := 0, DerivedObjects := {}
	static LBUTTONDOWNFunc := ObjBindMethod(TestClass, "WM_LBUTTONDOWN")	; store the BoundFunc object so you may remove the message handler
	static MouseHoverFunc := ObjBindMethod(TestClass, "WM_MOUSEHOVER")
	static MouseLeaveFunc := ObjBindMethod(TestClass, "WM_MOUSELEAVE")
	__New(wID, Name, x, y) {
		Gui, New, +Hwndhwnd
		Gui %hwnd%: -Caption +ToolWindow +OwnDialogs +LastFound +Owner%wID%
		Gui %hwnd%: margin, 0,0
		Gui %hwnd%: font,s55 bold
		Gui %hwnd%: add,text,,Hello
		Gui %hwnd%: color, 2a3139
		winset, transcolor, 2a3139
		Gui %hwnd%: Show, % "x" x " y" y " NA"
		this.hPos := hPos, this.hwnd := hwnd, this.Name := Name, this.wID := wID
		TestClass.DerivedObjectsCount += 1
		if (TestClass.DerivedObjectsCount > 0)
		{
			OnMessage(0x201, this.LBUTTONDOWNFunc)	; activate the message handler
			OnMessage(0x2A1, this.MouseHoverFunc)	
			OnMessage(0x2A3, this.MouseLeaveFunc)	
		}
		TestClass.DerivedObjects[hwnd] := &this		; store object's address
	}
	
	WM_MOUSELEAVE()
	{
		if (!TestClass.DerivedObjects.HasKey(A_Gui))
			return
		
		obj := Object(TestClass.DerivedObjects[A_Gui])
		winset, transcolor, 2a3139 255, % "ahk_id " obj.hwnd
	}
	
	WM_MOUSEHOVER()
	{
		if (!TestClass.DerivedObjects.HasKey(A_Gui))
			return
		
		obj := Object(TestClass.DerivedObjects[A_Gui])
		winset, trans, 175, % "ahk_id " obj.hwnd
	}
	
	WM_LBUTTONDOWN() 
	{
		static Last_X, Last_Y
		
		if (!TestClass.DerivedObjects.HasKey(A_Gui))
			return
	
		obj := Object(TestClass.DerivedObjects[A_Gui])
		coordmode, mouse, screen
		mousegetpos, mX, mY
		Last_X := mX, Last_Y := mY
		WinMoveRelative(obj.hwnd)

		while GetKeyState("LButton","P")
		{
			sleep 10
			
			mousegetpos, mX, mY
			
			rX := mX - Last_X
			rY := mY - Last_Y

			WinGetPos, x, y, w, h, % "ahk_id " obj.hwnd
			oClient := WinGetClientPos(obj.wID) 
			WinGetPos, , wY, ,wH , % "ahk_id " obj.wID
			
			oX := x + w
			oWX := oClient.X + oClient.W
			
			if (oX > oWX)
				rX := oWX - oX
			
			else if (x < oClient.X)
				rX := oClient.X - x
			
			oY := y + h
			oWY := wY + wH
			
			if (oY > oWY)
				rY := oWY - oY
			
			else if (y < wY)
				rY := wY - y
			
			WinMoveRelative(obj.hwnd,rX,rY)

			Last_X := mX
			Last_Y := mY

		}

		return 0    ; no need to call any other message handlers          
	}
	__Delete() {
		;MsgBox,,, % "Deleting " this.Name, 0.5
		hwnd := this.hwnd
		Gui %hwnd%: Destroy
		TestClass.DerivedObjects.Delete(hwnd)			; Lexikos: "Use .Delete(hwnd) or .Remove(hwnd, "") and not .Remove(hwnd)."
		TestClass.DerivedObjectsCount -= 1
		if (TestClass.DerivedObjectsCount = 0)			; if no more derived objects
		{
			OnMessage(0x201, this.LBUTTONDOWNFunc, 0)	; remove message handler
			OnMessage(0x2A1, this.MouseHoverFunc, 0)
			OnMessage(0x2A3, this.MouseLeaveFunc, 0)
		}
	}
}

WinGetClientPos(hwnd) 
{ ; takes a hwnd and returns an object with client X Y W H
	;https://www.autohotkey.com/boards/viewtopic.php?f=6&t=484
	VarSetCapacity( size, 16, 0 )
	DllCall( "GetClientRect", UInt, hwnd, Ptr, &size )
	DllCall( "ClientToScreen", UInt, hwnd, Ptr, &size )
	x := NumGet(size, 0, "Int")
	y := NumGet(size, 4, "Int")
	w := NumGet( size, 8, "Int" )
	h := NumGet( size, 12, "Int" )
	return { X: x, Y: y, W: w, H: h }
}

WinMoveRelative(hwnd,rX := 0,rY := 0,rW := 0,rH := 0)
{
	WinGetPos, cX, cY, cW, cH,% "ahk_id " hwnd
	winmove, % "ahk_id " hwnd,, cX + rX,cY + rY, cW + rW, cH + rH
}

doubledave22
Posts: 343
Joined: 08 Jun 2019, 17:36

Re: Need help with a drag+drop overlay class

Post by doubledave22 » 16 Jan 2022, 16:52

It seems I need to implement TrackMouseEvent inside the testclass I just cant seem to figure it out. I am trying to re-fit this @teadrinker script here: viewtopic.php?f=76&t=66518&p=286086&hilit=MouseHover#p286040 but definitely doing something wrong with TRACKMOUSEEVENT.

Things are a bit messy and I plan on cleaning all this up just need a working prototype. From what I can tell, TrackMouseEvent method is probably not initialized properly and no A_Gui value is getting sent therefore I can't access the instance obj to build out TRACKMOUSEEVENT properly

Code: Select all

#SingleInstance force

global WM_MOUSEMOVE  := 0x200
     , WM_MOUSEHOVER := 0x2A1
     , WM_MOUSELEAVE := 0x2A3
	 , SS_NOTIFY     := 0x100

return

^+d::
newwin := Winexist("A")
wingetpos, windowx, windowy, , , A
Test1 := new TestClass(newwin,"Test1", windowx+100, windowy+100)
return

class TestClass {
	static DerivedObjectsCount := 0, DerivedObjects := {}
	static LBUTTONDOWNFunc := ObjBindMethod(TestClass, "WM_LBUTTONDOWN")	; store the BoundFunc object so you may remove the message handler
	static mMouseEvent := ObjBindMethod(TestClass, "TrackMouseEvent")

	__New(wID, Name, x, y) {
		
		Gui, New, +Hwndhwnd
		Gui %hwnd%: -Caption +ToolWindow +OwnDialogs +LastFound +Owner%wID% %SS_NOTIFY%
		Gui %hwnd%: margin, 0,0
		Gui %hwnd%: font,s55 bold
		Gui %hwnd%: add,text, ,Hello
		Gui %hwnd%: color, 2a3139
		winset, transcolor, 2a3139
		Gui %hwnd%: Show, % "x" x " y" y " NA"
		
		this.hPos := hPos, this.hwnd := hwnd, this.Name := Name, this.wID := wID
		
		TestClass.DerivedObjectsCount += 1
		if (TestClass.DerivedObjectsCount > 0)
		{
			OnMessage(0x201, this.LBUTTONDOWNFunc)	; activate the message handler
			OnMessage(0x2A1, this.mMouseEvent)	
			OnMessage(0x2A3, this.mMouseEvent)	
		}
		TestClass.DerivedObjects[hwnd] := &this		; store object's address
		
		this.flags := (TME_HOVER := 1) | (TME_LEAVE := 2)
		this.hover := false
		this._hCtrl := ""
		this.TrackMouseEvent(hwnd, 10)
	}
	
	TrackMouseEvent(hCtrl, time, msg := "", hwnd := "") 
	{

		if (!TestClass.DerivedObjects.HasKey(A_Gui))	; doesnt appear to work in this method like in WM_LBUTTONDOWN
			return
		
		obj := Object(TestClass.DerivedObjects[A_Gui])
		
		_hCtrl := obj._hCtrl
		hover := obj.hover
		TRACKMOUSEEVENT := obj.TRACKMOUSEEVENT
		flags := obj.flags

	   if !msg {
		  obj._hCtrl := hCtrl
		  VarSetCapacity(TRACKMOUSEEVENT, len := 8 + A_PtrSize*2, 0)
		  NumPut(len   , TRACKMOUSEEVENT)
		  NumPut(obj.flags , TRACKMOUSEEVENT, 4)
		  NumPut(hCtrl , TRACKMOUSEEVENT, 8)
		  NumPut(time  , TRACKMOUSEEVENT, 8 + A_PtrSize, "UInt")
	   }
	   
	   if (!hover && hwnd = _hCtrl && msg = WM_MOUSEMOVE) {
		  hover := true
		  DllCall("TrackMouseEvent", "Ptr", &TRACKMOUSEEVENT)
		  tooltip moving
	   }
	   if (msg = WM_MOUSEHOVER)
	  {
		  tooltip hovering
	  }
	   if (msg = WM_MOUSELEAVE) {
		  hover := false
		   tooltip leaving

	   }
	}

	
	WM_LBUTTONDOWN() 
	{
		static Last_X, Last_Y
		
		if (!TestClass.DerivedObjects.HasKey(A_Gui))
			return
	
		obj := Object(TestClass.DerivedObjects[A_Gui])
		coordmode, mouse, screen
		mousegetpos, mX, mY
		Last_X := mX, Last_Y := mY
		WinMoveRelative(obj.hwnd)

		while GetKeyState("LButton","P")
		{
			sleep 10
			
			mousegetpos, mX, mY
			
			rX := mX - Last_X
			rY := mY - Last_Y

			WinGetPos, x, y, w, h, % "ahk_id " obj.hwnd
			oClient := WinGetClientPos(obj.wID) 
			WinGetPos, , wY, ,wH , % "ahk_id " obj.wID
			
			oX := x + w
			oWX := oClient.X + oClient.W
			
			if (oX > oWX)
				rX := oWX - oX
			
			else if (x < oClient.X)
				rX := oClient.X - x
			
			oY := y + h
			oWY := wY + wH
			
			if (oY > oWY)
				rY := oWY - oY
			
			else if (y < wY)
				rY := wY - y
			
			WinMoveRelative(obj.hwnd,rX,rY)

			Last_X := mX
			Last_Y := mY

		}

		return 0    ; no need to call any other message handlers          
	}
	__Delete() {
		;MsgBox,,, % "Deleting " this.Name, 0.5
		hwnd := this.hwnd
		Gui %hwnd%: Destroy
		TestClass.DerivedObjects.Delete(hwnd)			; Lexikos: "Use .Delete(hwnd) or .Remove(hwnd, "") and not .Remove(hwnd)."
		TestClass.DerivedObjectsCount -= 1
		if (TestClass.DerivedObjectsCount = 0)			; if no more derived objects
		{
			OnMessage(0x201, this.LBUTTONDOWNFunc, 0)	; remove message handler
			OnMessage(0x2A1, this.MouseHoverFunc, 0)
			OnMessage(0x2A3, this.MouseLeaveFunc, 0)
		}
	}
}

WinGetClientPos(hwnd) 
{ ; takes a hwnd and returns an object with client X Y W H
	;https://www.autohotkey.com/boards/viewtopic.php?f=6&t=484
	VarSetCapacity( size, 16, 0 )
	DllCall( "GetClientRect", UInt, hwnd, Ptr, &size )
	DllCall( "ClientToScreen", UInt, hwnd, Ptr, &size )
	x := NumGet(size, 0, "Int")
	y := NumGet(size, 4, "Int")
	w := NumGet( size, 8, "Int" )
	h := NumGet( size, 12, "Int" )
	return { X: x, Y: y, W: w, H: h }
}

WinMoveRelative(hwnd,rX := 0,rY := 0,rW := 0,rH := 0)
{
	WinGetPos, cX, cY, cW, cH,% "ahk_id " hwnd
	winmove, % "ahk_id " hwnd,, cX + rX,cY + rY, cW + rW, cH + rH
}

Post Reply

Return to “Ask for Help (v1)”