#include-once
#Include <FontConstants.au3>
#include <GDIPlus.au3>
#include <GUIConstantsEx.au3>
#include <StaticConstants.au3>
#include <WinAPISysInternals.au3>
#include <WinAPISysWin.au3>
#include <WindowsConstants.au3>

_GDIPlus_Startup()
Global $__g_hCalcFontSize = DllCallbackRegister('__CalcFontSizeProc', 'ptr', 'hwnd;uint;long;ptr')
Global $__g_pCalcFontSize = DllCallbackGetPtr($__g_hCalcFontSize)
Global $__g_aCalcFontSize[0][2]
Global Const $__g_sCalcFontSize_Version = '1.1.0.0'
Global Const $__g_sCalcFontSize_Date = '2021/10/09 08:00:00'
OnAutoItExitRegister('__CalcFontSizeExit')

Func __CalcFontSizeExit()
	Local $iCount = UBound($__g_aCalcFontSize)
	If $iCount > 0 Then
		For $i = 0 To $iCount - 1
			_WinAPI_SetWindowLong($__g_aCalcFontSize[$i][0], $GWL_WNDPROC, $__g_aCalcFontSize[$i][1])
		Next
	EndIf
	DllCallbackFree($__g_hCalcFontSize)
	_GDIPlus_Shutdown()
EndFunc

; ============================================================================================================
; Name...........: _CalcFontSizeRegister
; Description ...: Registriert ein Gui-Element (Label/Button) fuer die automatische Fontgroesse
; Syntax.........: _CalcFontSizeRegister($hWnd)
; Parameters ....: $hWnd = das Handle oder die Control-ID des Gui-Elements
; Return values .: bei Erfolg = 1
;                  im Fehlerfall 0 und @error =
;                     1: $hWnd ist kein Window-Handle
;                     2: das Gui-Element ist bereits registriert
; Author ........: Oscar (www.autoit.de)
; ============================================================================================================
Func _CalcFontSizeRegister($hWnd)
    If Not IsHWnd($hWnd) Then $hWnd = GUICtrlGetHandle($hWnd)
	If Not IsHWnd($hWnd) Then Return SetError(1, 0, 0)
	__CalcFontSizeGetIndex($hWnd)
	If Not @error Then Return SetError(2, 0, 0)
	Local $iCount = UBound($__g_aCalcFontSize)
	ReDim $__g_aCalcFontSize[$iCount + 1][2]
	$__g_aCalcFontSize[$iCount][0] = $hWnd
	$__g_aCalcFontSize[$iCount][1] = _WinAPI_SetWindowLong($hWnd, $GWL_WNDPROC, $__g_pCalcFontSize)
	_CalcFontSize($hWnd) ; beim registrieren einmalig die Fontgroesse berechnen
	Return 1
EndFunc

; ============================================================================================================
; Name...........: _CalcFontSizeUnregister
; Description ...: Entfernt die automatische Font-Anpassung
; Syntax.........: _CalcFontSizeUnregister($hWnd)
; Parameters ....: $hWnd = das Handle oder die Control-ID des Gui-Elements
; Return values .: bei Erfolg = 1
;                  im Fehlerfall 0 und @error =
;                     1: $hWnd ist kein Window-Handle
;                     2: das Gui-Element ist nicht registriert
; Author ........: Oscar (www.autoit.de)
; ============================================================================================================
Func _CalcFontSizeUnregister($hWnd)
    If Not IsHWnd($hWnd) Then $hWnd = GUICtrlGetHandle($hWnd)
	If Not IsHWnd($hWnd) Then Return SetError(1, 0, 0)
	Local $iIndex = __CalcFontSizeGetIndex($hWnd)
	If @error Then Return SetError(2, 0, 0)
	_WinAPI_SetWindowLong($__g_aCalcFontSize[$iIndex][0], $GWL_WNDPROC, $__g_aCalcFontSize[$iIndex][1])
	$__g_aCalcFontSize[$iIndex][0] = $__g_aCalcFontSize[UBound($__g_aCalcFontSize) - 1][0]
	$__g_aCalcFontSize[$iIndex][1] = $__g_aCalcFontSize[UBound($__g_aCalcFontSize) - 1][1]
	ReDim $__g_aCalcFontSize[UBound($__g_aCalcFontSize) - 1][2]
	Return 1
EndFunc

; ============================================================================================================
; Name...........: __CalcFontSizeGetIndex
; Description ...: Ermittelt den Array-Index (nur interner Gebrauch)
; Syntax.........: __CalcFontSizeGetIndex($hWnd)
; Parameters ....: $hWnd = das Handle des Gui-Elements
; Return values .: bei Erfolg = Array-Index
;                  im Fehlerfall 0 und @error =
;                     1: Handle befindet sich nicht im Array
; Author ........: Oscar (www.autoit.de)
; ============================================================================================================
Func __CalcFontSizeGetIndex($hWnd)
	For $iIndex = 0 to UBound($__g_aCalcFontSize) - 1
		If $hWnd = $__g_aCalcFontSize[$iIndex][0] Then Return $iIndex
	Next
	Return SetError(1, 0, 0)
EndFunc

; ============================================================================================================
; Name...........: __CalcFontSizeProc
; Description ...: Callback-Funktion - WindowProcedur (nur interner Gebrauch)
; Syntax.........: __CalcFontSizeProc($hWnd, $iMsg, $wParam, $lParam)
; Author ........: Oscar (www.autoit.de)
; ============================================================================================================
Func __CalcFontSizeProc($hWnd, $iMsg, $wParam, $lParam)
	Local $iIndex = __CalcFontSizeGetIndex($hWnd)
	Switch $iMsg
		Case $WM_DESTROY
			_CalcFontSizeUnregister($hWnd)
		Case $WM_NCCALCSIZE
			Local $tRect = DllStructCreate($tagRECT, $lParam)
			Local $iW = $tRect.right - $tRect.left, $iH = $tRect.bottom - $tRect.top
			__CalcFontSize($hWnd, $iW, $iH)
	EndSwitch
	Return _WinAPI_CallWindowProc($__g_aCalcFontSize[$iIndex][1], $hWnd, $iMsg, $wParam, $lParam)
EndFunc

; ============================================================================================================
; Name...........: _CalcFontSize
; Description ...: Berechnet die Fontgroesse fuer das Gui-Element (einmalig, ohne Registrierung)
; Syntax.........: _CalcFontSize($hWnd)
; Parameters ....: $hWnd = das Handle oder die Ctrl-ID des Gui-Elements
; Return values .: bei Erfolg = die berechnete Fontgroesse
;                  im Fehlerfall 0 und @error =
;                     1: die Fontdaten konnten nicht ermittelt werden
; Author ........: Oscar (www.autoit.de)
; ============================================================================================================
Func _CalcFontSize($hWnd)
    If Not IsHWnd($hWnd) Then $hWnd = GUICtrlGetHandle($hWnd)
	If Not IsHWnd($hWnd) Then Return SetError(1, 0, 0)
	Local $tRect = _WinAPI_GetClientRect($hWnd)
	Return __CalcFontSize($hWnd, $tRect.Right, $tRect.Bottom)
EndFunc

; ============================================================================================================
; Name...........: __CalcFontSize
; Description ...: Berechnet die Fontgroesse (nur interner Gebrauch)
; Syntax.........: __CalcFontSize($hWnd)
; Parameters ....: $hWnd = das Handle des Gui-Elements
;                  $iW = Breite (Width)
;                  $iH = Hoehe (Height)
; Return values .: bei Erfolg = die berechnete Fontgroesse
;                  im Fehlerfall 0 und @error =
;                     1: die Fontdaten konnten nicht ermittelt werden
; Author ........: Oscar (www.autoit.de)
; ============================================================================================================
Func __CalcFontSize($hWnd, $iW, $iH)
	Local $sText, $hGraphic, $hFormat, $hFamily, $iFontSize, $hFont, $tLayout, $aInfo
	Local $tFont = _GuiCtrlGetFont($hWnd)
	if @error Then Return SetError(1, 0, 0)
	$sText = _WinAPI_GetWindowText($hWnd)
	$hGraphic = _GDIPlus_GraphicsCreateFromHWND($hWnd)
	$hFormat = _GDIPlus_StringFormatCreate()
	$hFamily = _GDIPlus_FontFamilyCreate($tFont.FaceName)
	$tLayout = _GDIPlus_RectFCreate(0, 0, $iW, $iH)
	$iFontSize = Int($iH / 1.66) ; Ein groesserer Font als die Hoehe in Pixel passt nicht
	Do
		$iFontSize -= 1
		if $iFontSize = 0 Then ExitLoop
		$hFont = _GDIPlus_FontCreate($hFamily, $iFontSize, $tFont.Style)
		$aInfo = _GDIPlus_GraphicsMeasureString($hGraphic, $sText, $hFont, $tLayout, $hFormat)
		_GDIPlus_FontDispose($hFont)
	Until ($aInfo[1] >= StringLen($sText)) and ($aInfo[2] * $iFontSize * 1.66 < $iH)
	_GDIPlus_FontFamilyDispose($hFamily)
	_GDIPlus_StringFormatDispose($hFormat)
	_GDIPlus_GraphicsDispose($hGraphic)
	If $iFontSize Then
		GUICtrlSetFont(_WinAPI_GetDlgCtrlID($hWnd), $iFontSize, $tFont.Weight, $tFont.Style, $tFont.FaceName, $tFont.Quality)
	EndIf
	Return $iFontSize
EndFunc

; ============================================================================================================
; Name...........: _GuiCtrlGetFont
; Description ...: Gibt eine Struktur mit den Fontdaten des Gui-Elements zurueck
; Syntax.........: _GuiCtrlGetFont($hWnd)
; Parameters ....: $hWnd = das Handle oder die Control-ID des Gui-Elements
; Return values .: bei Erfolg = eine Struktur mit den Fontdaten (Height, Weight, Style, Name, Quality)
;                  im Fehlerfall ist @error =
;                     1: $hWnd ist kein Window-Handle
;                     2: die Fontdaten konnten nicht ermittelt werden
; Author ........: Oscar (www.autoit.de)
; ============================================================================================================
Func _GuiCtrlGetFont($hWnd)
	Local $tFont = DllStructCreate('int Height;int Weight;byte Style;char FaceName[32];byte Quality;')
    If Not IsHWnd($hWnd) Then $hWnd = GUICtrlGetHandle($hWnd)
	If Not IsHWnd($hWnd) Then Return SetError(1, 0, $tFont)
	Local $hFont = _SendMessage($hWnd, $WM_GETFONT)
	Local $tLF = DllStructCreate($tagLOGFONT)
	Local $ret = _WinAPI_GetObject($hFont, DllStructGetSize($tLF), DllStructGetPtr($tLF))
	If Not $ret Then Return SetError(2, 0, $tFont)
	Local $hDC = _WinAPI_GetDC($hWnd)
	$tFont.Height = -Int($tLF.Height / _WinAPI_GetDeviceCaps($hDC, $LOGPIXELSY) * 72)
	$tFont.Weight = $tLF.Weight
	$tFont.Style = BitOR(($tLF.Italic <> 0) * 2, ($tLF.Underline <> 0) * 4, ($tLF.StrikeOut <> 0) * 8)
	$tFont.FaceName = $tLF.FaceName
	$tFont.Quality = $tLF.Quality
	_WinAPI_ReleaseDC($hWnd, $hDC)
	Return $tFont
EndFunc
