﻿;-- TIME_STAMP   2018-07-08 16:47:21   v 0.1

#include-once
#include <AutoItConstants.au3>
#include <StructureConstants.au3>
#include <WinAPI.au3>
#include <WinAPIGdi.au3>
#include <WinAPISys.au3>
#include <WindowsConstants.au3>

OnAutoItExitRegister('_WindowDocking_Exit')

Global $__g_ahDocking_Gui[0][3]
Global $__g_hDocking_ProcNew = DllCallbackRegister('_WindowDocking_Proc', 'ptr', 'hwnd;uint;wparam;lparam')

Global Const $__g_sDocking_Version = '1.3.0.0'
Global Const $__g_sDocking_Date = '2018/07/07 19:25:00'

Func _WindowDocking_Exit()
	For $i = 0 To UBound($__g_ahDocking_Gui) - 1
		_WinAPI_SetWindowLong($__g_ahDocking_Gui[$i][0], $GWL_WNDPROC, DllCallbackGetPtr($__g_ahDocking_Gui[$i][1]))
	Next
	DllCallbackFree($__g_hDocking_ProcNew)
EndFunc  ;==>_WindowDocking_Exit

Func _WindowDocking_Add($hWnd, $iMagneticBorder = 50)
	If Not IsHWnd($hWnd) Then Return SetError(1)
	Local $iCount = UBound($__g_ahDocking_Gui)
	ReDim $__g_ahDocking_Gui[$iCount + 1][3]
	$__g_ahDocking_Gui[$iCount][0] = $hWnd
	$__g_ahDocking_Gui[$iCount][1] = _WinAPI_SetWindowLong($__g_ahDocking_Gui[$iCount][0], $GWL_WNDPROC, DllCallbackGetPtr($__g_hDocking_ProcNew))
	$__g_ahDocking_Gui[$iCount][2] = $iMagneticBorder
EndFunc  ;==>_WindowDocking_Add

Func _WindowDocking_Remove($hWnd)
	If Not IsHWnd($hWnd) Then Return SetError(1, 0, False)
	Local $iCount = UBound($__g_ahDocking_Gui)
	For $iIndex = 0 To $iCount - 1
		If $__g_ahDocking_Gui[$iIndex][0] = $hWnd Then
			_WinAPI_SetWindowLong($__g_ahDocking_Gui[$iIndex][0], $GWL_WNDPROC, DllCallbackGetPtr($__g_ahDocking_Gui[$iIndex][1]))
			If $iCount > 1 Then
				For $j = 0 To 2
					$__g_ahDocking_Gui[$iIndex][$j] = $__g_ahDocking_Gui[$iCount - 1][$j]
				Next
			EndIf
			ReDim $__g_ahDocking_Gui[$iCount - 1][3]
			Return SetError(0, 0, True)
		EndIf
	Next
	Return SetError(2, 0, False)
EndFunc  ;==>_WindowDocking_Remove

Func _WindowDocking_SetMagneticBorder($hWnd, $iMagneticBorder)
	If Not IsHWnd($hWnd) Then Return SetError(1, 0, False)
	Local $iCount = UBound($__g_ahDocking_Gui)
	For $iIndex = 0 To $iCount - 1
		If $__g_ahDocking_Gui[$iIndex][0] = $hWnd Then
			$__g_ahDocking_Gui[$iIndex][2] = $iMagneticBorder
			Return True
		EndIf
	Next
	Return SetError(3, 0, False)
EndFunc

Func _WindowDocking_Proc($hWnd, $iMsg, $wParam, $lParam)
	Local Const $iCX = _WinAPI_GetSystemMetrics($SM_CXSIZEFRAME), $iCY = _WinAPI_GetSystemMetrics($SM_CYSIZEFRAME)
	Local Static $iInRect = 0
	Local $hProcOld, $hMonitor, $aInfo, $iLeft, $iTop, $iRight, $iBottom, $tWindowPos, $tPoint_LeftTop, $tPoint_RightBottom, $iMagneticBorder, $iCount = UBound($__g_ahDocking_Gui)
	For $iIndex = 0 To $iCount - 1
		If $__g_ahDocking_Gui[$iIndex][0] = $hWnd Then ExitLoop
	Next
	$iMagneticBorder = $__g_ahDocking_Gui[$iIndex][2]
	Switch $iMsg
		Case $WM_WINDOWPOSCHANGING
			$hMonitor = _WinAPI_MonitorFromWindow($hWnd)
			$aInfo = _WinAPI_GetMonitorInfo($hMonitor)
			$tWindowPos = DllStructCreate($tagWINDOWPOS, $lParam)
			$iLeft   = DllStructGetData($tWindowPos, 'X')
			$iTop    = DllStructGetData($tWindowPos, 'Y')
			$iRight  = DllStructGetData($tWindowPos, 'CX')
			$iBottom = DllStructGetData($tWindowPos, 'CY')

			$tPoint_LeftTop     = _WinAPI_CreatePoint($iLeft, $iTop)
			$tPoint_RightBottom = _WinAPI_CreatePoint($iRight, $iBottom)
			If _WinAPI_PtInRect($aInfo[1], $tPoint_LeftTop) And _WinAPI_PtInRect($aInfo[1], $tPoint_LeftTop) Then
				Select
					; Check Left
					Case DllStructGetData($tWindowPos, 'X') < DllStructGetData($aInfo[1], 'Left') + $iCX + $iMagneticBorder
						DllStructSetData($tWindowPos, 'X', DllStructGetData($aInfo[1], 'Left') + $iCX)
					; Check Right
					Case DllStructGetData($tWindowPos, 'X') + DllStructGetData($tWindowPos, 'CX') > DllStructGetData($aInfo[1], 'Right') - $iCX - $iMagneticBorder
						DllStructSetData($tWindowPos, 'X', DllStructGetData($aInfo[1], 'Right') - DllStructGetData($tWindowPos, 'CX') - $iCX)
					; Check Top
					Case DllStructGetData($tWindowPos, 'Y') < DllStructGetData($aInfo[1], 'Top') + $iCY + $iMagneticBorder
						DllStructSetData($tWindowPos, 'Y', DllStructGetData($aInfo[1], 'Top') + $iCY)
					; Check Bottom
					Case DllStructGetData($tWindowPos, 'Y') + DllStructGetData($tWindowPos, 'CY') > DllStructGetData($aInfo[1], 'Bottom') - $iCY - $iMagneticBorder
						DllStructSetData($tWindowPos, 'Y', DllStructGetData($aInfo[1], 'Bottom') - DllStructGetData($tWindowPos, 'CY') - $iCY)
				EndSelect
			EndIf
	EndSwitch
	Return _WinAPI_CallWindowProc($__g_ahDocking_Gui[$iIndex][1], $hWnd, $iMsg, $wParam, $lParam)
EndFunc  ;==>_WindowDocking_Proc
