;*******************************************************************
;***              ThemedOwnerdraw.au3
;***
;***     Demonstriert, wie man Visuelle Stile in selbstgezeichneten
;***     Steuerelementen benutzen kann.
;***
;***     Greenhorn, 2010
;***

; Für optimale Ansicht Tabgröße auf 5 einstellen.


#include <Constants.au3>
#include <GuiConstantsEx.au3>
#include <WindowsConstants.au3>
#include <ButtonConstants.au3>

OnAutoItExitRegister ("AppExit")

; --- RECT
Global Const $_RECT = _
	"long left;" & _
	"long top;" & _
	"long right;" & _
	"long bottom;"

; --- $DRAWITEMSTRUCT
Global Const $DRAWITEMSTRUCT = _
		'uint CtlType;'& _
		'uint CtlID;'& _
		'uint itemID;'& _
		'uint itemAction;'& _
		'uint itemState;'& _
		'hwnd hwndItem;'& _
		'ptr hDC;'& _
		'long rcItem[4];'& _
		'ulong_ptr itemData;'

; --- $TRACKMOUSEEVENT
Global Const $TRACKMOUSEEVENT = _
	'dword cbSize;'& _
	'dword dwFlags;'& _
	'hwnd  hwndTrack;'& _
	'dword dwHoverTime;'

; --- LOGFONT
Global Const $LOGFONT = _
	'LONG lfHeight;'& _
	'LONG lfWidth;'& _
	'LONG lfEscapement;'& _
	'LONG lfOrientation;'& _
	'LONG lfWeight;'& _
	'BYTE lfItalic;'& _
	'BYTE lfUnderline;'& _
	'BYTE lfStrikeOut;'& _
	'BYTE lfCharSet;'& _
	'BYTE lfOutPrecision;'& _
	'BYTE lfClipPrecision;'& _
	'BYTE lfQuality;'& _
	'BYTE lfPitchAndFamily;'& _
	'WCHAR lfFaceName [32];'


Global Const $S_OK	= 0

Global Const $_TME_HOVER	= 1
Global Const $_TME_LEAVE	= 2

Global Const $WM_MOUSEHOVER  = 0x02A1
Global Const $WM_MOUSELEAVE  = 0x02A3
Global Const $WM_THEMECHANGED = 0x031A

Global Const $NULL = Ptr(0)

Global Const $GWLP_WNDPROC = $GWL_WNDPROC
Global Const $GWLP_USERDATA = -21

Global Const $ODT_BUTTON	= 4

Global Const $ODA_DRAWENTIRE = 0x0001
Global Const $ODA_SELECT = 0x0002
Global Const $ODA_FOCUS = 0x0004
Global Const $ODS_SELECTED = 0x0001
Global Const $ODS_GRAYED = 0x0002
Global Const $ODS_DISABLED = 0x0004
Global Const $ODS_CHECKED = 0x0008
Global Const $ODS_FOCUS = 0x0010
Global Const $ODS_HOTLIGHT = 0x0040
Global Const $ODS_INACTIVE = 0x0080
Global Const $ODS_NOACCEL = 0x0100
Global Const $ODS_NOFOCUSRECT = 0x0200

Global Enum $PBS_NORMAL = 1, _
	$PBS_HOT, _
	$PBS_PRESSED, _
	$PBS_DISABLED, _
	$PBS_DEFAULTED, _
	$PBS_DEFAULTED_ANIMATING

Global Const $BP_PUSHBUTTON = 1

Global Const $TMT_FONT	= 210
Global Const $TMT_MENUFONT	= 803

Global $g_hTheme
Global $uxthemedll

Global $g_hButtonProc = $NULL
Global $g_hOldButtonProc = $NULL
Global $g_bMouseMove = FALSE

Global $ID_BUTTON_0
Global $ID_BUTTON_1


;««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

Global $uxthemedll  = DllOpen ("uxtheme.dll")
Global $user32dll	= DllOpen ("user32.dll")
Global $gdi32dll	= DllOpen ("gdi32.dll")

If ($uxthemedll == -1) Then
	ConsoleWrite ("! g_hThemeLib = "&$uxthemedll & @crlf)
	Exit (-1)
Else
	Exit (MainDlg ( ))
EndIf

;««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

Func MainDlg ( )

	Local $hWnd
	Local $hwndButton_1

	$hWnd = GUICreate ("Themed Ownerdraw Demo", 400, 300)

	$ID_BUTTON_0 = GUICtrlCreateButton ("Ownerdraw", 25,  85, 350, 90)
	$ID_BUTTON_1 = GUICtrlCreateButton ("Standard",  25, 185, 350, 90)

	GUICtrlSetStyle ($ID_BUTTON_0, BitOR($WS_TABSTOP, $BS_NOTIFY, $BS_OWNERDRAW))
	GUICtrlSetTip ($ID_BUTTON_0, "Selbstgezeichnete Schaltfläche")
	GUICtrlSetTip ($ID_BUTTON_1, "Standard Schaltfläche")


	; Die Fensterprozedur der Schaltfläche durch unsere eigene ersetzen.
	$g_hButtonProc = DllCallbackRegister ("ButtonProc", "LONG", "HWND;UINT;WPARAM;LPARAM")

	If ($g_hButtonProc) Then
		$g_hOldButtonProc = SetWindowLongPtr ( _
							GUICtrlGetHandle ($ID_BUTTON_0) , _
							$GWLP_WNDPROC, _
							DllCallbackGetPtr ($g_hButtonProc) _
							)
	EndIf

	$g_hTheme = OpenThemeData ($hwnd, "Button")

	If ($g_hTheme) Then
		GUIRegisterMsg ($WM_THEMECHANGED,  "WM_THEMECHANGED")
	EndIf

	GUIRegisterMsg ($WM_DRAWITEM,  "WM_DRAWITEM")

	GUISetState (@SW_SHOW, $hWnd)

	While (TRUE)

		Switch (GUIGetMsg ( ))
			Case $GUI_EVENT_CLOSE
				ExitLoop
		EndSwitch
	WEnd

	Return 0

EndFunc

Func WM_DRAWITEM ($hwnd, $message, $wParam, $lParam)

	Local $dis = DllStructCreate ($DRAWITEMSTRUCT, $lParam)
	Local $hDC         = DllStructGetData ($dis, "hDC")
	Local $hwndItem    = DllStructGetData ($dis, "hwndItem")
	Local $nItemAction = DllStructGetData ($dis, "itemAction")
	Local $nItemState  = DllStructGetData ($dis, "itemState")

	Local $lprcItem = DllStructGetPtr ($dis, "rcItem")

	Local $bChecked    = BitAND($nItemState, $ODS_CHECKED)
	Local $bFocused    = BitAND($nItemState, $ODS_FOCUS)
	Local $bGrayed     = BitAND($nItemState, BitOR($ODS_GRAYED, $ODS_DISABLED))
	Local $bSelected   = BitAND($nItemState, $ODS_SELECTED)
	Local $bHotlighted = BitAND($nItemState, $ODS_HOTLIGHT)


	If ($nItemAction == $ODA_DRAWENTIRE) Then

		If ($g_hTheme) Then

			If ($bFocused) Then
				If ($bSelected) Then
					DrawControlTheme ($hDC, $lprcItem, $hwndItem, $g_hTheme, $PBS_PRESSED)
				Else
					DrawControlTheme ($hDC, $lprcItem, $hwndItem, $g_hTheme, $PBS_DEFAULTED)
				EndIf
				InflateRect ($lprcItem, -3, -3)
				DrawFocusRect ($hDC, $lprcItem)
			Else
				DrawControlTheme ($hDC, $lprcItem, $hwndItem, $g_hTheme, $PBS_NORMAL)
			EndIf
		Else
			; Die Schaltfläche ohne Visuellen Stil zeichnen.
		EndIf

	ElseIf ($nItemAction == $ODA_FOCUS) Then

		If ($g_hTheme) Then

			If ($bFocused) Then
				DrawControlTheme ($hDC, $lprcItem, $hwndItem, $g_hTheme, $PBS_DEFAULTED)
			EndIf
			If ($bSelected) Then
				DrawControlTheme ($hDC, $lprcItem, $hwndItem, $g_hTheme, $PBS_PRESSED)
			EndIf
		Else
			; Die Schaltfläche ohne Visuellen Stil zeichnen.
		EndIf
		InflateRect ($lprcItem, -3, -3)
		DrawFocusRect ($hDC, $lprcItem)

	EndIf

	If ($bHotlighted) Then

		DrawControlTheme ($hDC, $lprcItem, $hwndItem, $g_hTheme, $PBS_HOT)

		If ($g_hTheme) Then

			If ($bFocused) Then
				InflateRect ($lprcItem, -3, -3)
				DrawFocusRect ($hDC, $lprcItem)
			EndIf
			If ($bSelected) Then
				DrawControlTheme ($hDC, $lprcItem, $hwndItem, $g_hTheme, $PBS_PRESSED)
			EndIf
		Else
			; Die Schaltfläche ohne Visuellen Stil zeichnen.
		EndIf
	EndIf

	Return TRUE

EndFunc

Func WM_THEMECHANGED ($hwnd, $message, $wParam, $lParam)

	; Der Visuelle Stil wurde geändert.

	If ($g_hTheme) Then

		CloseThemeData ($g_hTheme)
		$g_hTheme = OpenThemeData ($hwnd, "Button")
	EndIf

	Return $GUI_RUNDEFMSG

EndFunc

Func AppExit ( )

	if ($uxthemedll) then
		if ($g_hTheme) then
			CloseThemeData ($g_hTheme)
		endif
		DllClose ($uxthemedll)
		DllClose ($user32dll)
		DllClose ($gdi32dll)
	endif

	if ($g_hButtonProc) then
		DllCallbackFree ($g_hButtonProc)
	endif

EndFunc

;««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

Func DrawControlTheme ($hDC, $lprect, $hwndButton, $hTheme, $iState)

	Local $rc = DllStructCreate ($_RECT, $lprect)
	Local $rcContent = DllStructCreate ($_RECT)
	Local $szButtonText
	Local $hr
	Local $cch
	Local $lf
	Local $hFont, $hFontOld

	$szButtonText = WinGetTitle ($hwndButton)
	$cch = StringLen ($szButtonText)

	if ($hTheme) then

		$lf = DllStructCreate ($LOGFONT)

		$hr = DrawThemeBackground ($hTheme, $hDC, $BP_PUSHBUTTON, _
				$iState, DllStructGetPtr ($rc), 0)

		$hr = GetThemeBackgroundContentRect ($hTheme, $hDC, $BP_PUSHBUTTON, _
				$iState, DllStructGetPtr ($rc), DllStructGetPtr ($rcContent))

		$hr = GetThemeSysFont ($hTheme, $TMT_MENUFONT, DllStructGetPtr ($lf))

		If ($hr <> $S_OK) Then
			DllStructSetData ($lf, "lfFaceName", "Tahoma")
			DllStructSetData ($lf, "lfWeight", 400)
		EndIf

		$hFont = CreateFontIndirect (DllStructGetPtr ($lf))

		$hFontOld = SelectObject ($hDC, $hFont)

		$hr = DrawThemeText ($hTheme, $hDC, $BP_PUSHBUTTON, $iState, _
				$szButtonText, $cch, _
				BitOR ($DT_CENTER, $DT_VCENTER, $DT_SINGLELINE), _
				0, DllStructGetPtr ($rcContent))

		DeleteObject (SelectObject ($hDC, $hFontOld))
    endif

EndFunc

;««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

Func ButtonProc ($hwnd, $message, $wParam, $lParam)

	Switch ($message)

		Case $WM_MOUSEMOVE

			Local $tme = DllStructCreate ($TRACKMOUSEEVENT)

			DllStructSetData ($tme, "cbSize"     , DllStructGetSize ($tme))
			DllStructSetData ($tme, "dwFlags"    , BitOR ($_TME_HOVER, $_TME_LEAVE))
			DllStructSetData ($tme, "dwHoverTime", 50)
			DllStructSetData ($tme, "hwndTrack"  , $hwnd)

			TrackMouseEvent (DllStructGetPtr ($tme))

			; Die Nachricht an die originale Fensterprozedur weiterleiten.
			CallWindowProc ($g_hOldButtonProc, $hwnd, $message, $wParam, $lParam)

			ContinueCase	; AutoIt ist einfach zu langsam, also gleich weiter ...

		Case $WM_MOUSEHOVER

			If (not $g_bMouseMove) Then

				Local $dis = DllStructCreate ($DRAWITEMSTRUCT)

				GetClientRect ($hwnd, DllStructGetPtr ($dis, "rcItem"))

				If (GetFocus ( ) == $hwnd) Then
					DllStructSetData ($dis, "itemState", BitOR ($ODS_HOTLIGHT, $ODS_FOCUS))
				Else
					DllStructSetData ($dis, "itemState", $ODS_HOTLIGHT)
				EndIf


				DllStructSetData ($dis, "CtlType", $ODT_BUTTON)
				DllStructSetData ($dis, "CtlID", GetDlgCtrlID ($hwnd))
				DllStructSetData ($dis, "itemID", 0)
				DllStructSetData ($dis, "itemAction", 0)
				DllStructSetData ($dis, "hwndItem", $hwnd)
				DllStructSetData ($dis, "hDC", GetDC ($hwnd))
				DllStructSetData ($dis, "itemData", $NULL)

				WM_DRAWITEM ($hwnd, $message, $wParam, DllStructGetPtr ($dis))

				ReleaseDC ($hwnd, DllStructGetData ($dis, "hDC"))
			EndIf

			$g_bMouseMove = TRUE

		Case $WM_MOUSELEAVE

			If ($g_bMouseMove) Then

				Local $dis = DllStructCreate ($DRAWITEMSTRUCT)

				GetClientRect ($hwnd, DllStructGetPtr ($dis, "rcItem"))

				If (GetFocus ( ) == $hwnd) Then
					DllStructSetData ($dis, "itemState",  $ODS_FOCUS)
					DllStructSetData ($dis, "itemAction", $ODA_FOCUS)
				Else
					DllStructSetData ($dis, "itemState",  $ODS_NOFOCUSRECT)
					DllStructSetData ($dis, "itemAction", $ODA_DRAWENTIRE)
				EndIf


				DllStructSetData ($dis, "CtlType", $ODT_BUTTON)
				DllStructSetData ($dis, "CtlID", GetDlgCtrlID ($hwnd))
				DllStructSetData ($dis, "itemID", 0)
				DllStructSetData ($dis, "hwndItem", $hwnd)
				DllStructSetData ($dis, "hDC", GetDC ($hwnd))
				DllStructSetData ($dis, "itemData", $NULL)

				WM_DRAWITEM ($hwnd, $message, $wParam, DllStructGetPtr ($dis))

				ReleaseDC ($hwnd, DllStructGetData ($dis, "hDC"))
			EndIf

			$g_bMouseMove = FALSE

		Case $WM_DESTROY
			; Die originale Fensterprozedur dem Fenster wieder zuordnen.
			SetWindowLongPtr ($hwnd, $GWLP_WNDPROC, $g_hOldButtonProc)

			; Die Nachricht an die originale Fensterprozedur senden.
			Return CallWindowProc ($g_hOldButtonProc, $hwnd, $message, $wParam, $lParam)

		Case Else
			; Die Nachricht an die originale Fensterprozedur weiterleiten.
			Return CallWindowProc ($g_hOldButtonProc, $hwnd, $message, $wParam, $lParam)
	EndSwitch

	Return 0

EndFunc

;««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

Func CallWindowProc ($lpPrevWndFunc, $hWnd, $Msg, $wParam, $lParam)

	Local $aRes = DllCall ($user32dll, 'ulong', 'CallWindowProcW', _
								'ptr',    $lpPrevWndFunc, _
								'hwnd',   $hWnd, _
								'uint',   $Msg, _
								'wparam', $wParam, _
								'lparam', $lParam)
	Return $aRes[0]

EndFunc

Func CreateFontIndirect ($lplf)

	Local $aRes = DllCall ($gdi32dll, 'ptr', 'CreateFontIndirectW', _
								'ptr', $lplf)   ; characteristics
	Return $aRes[0]

EndFunc

Func DeleteObject ($hObject)

	Local $aRes = DllCall ($gdi32dll, 'int', 'DeleteObject', _
							'ptr', $hObject)   ; handle to graphic object
	Return $aRes[0]

EndFunc

Func DrawFocusRect ($hDC, $lprc)

	Local $aRes = DllCall ('user32.dll', 'int', 'DrawFocusRect', _
										'ptr', $hDC, _          ; handle to device context
										'ptr', $lprc)  ; logical coordinates
	Return $aRes[0]

EndFunc

Func GetClientRect ($hWnd, $lpRect)

	Local $aRes = DllCall ($user32dll, 'int', 'GetClientRect', _
								'hwnd', $hWnd, _
								'ptr', $lpRect)
	Return $aRes[0]

EndFunc

Func GetDC ($hWnd)

	Local $aRes = DllCall ($user32dll, 'ptr', 'GetDC', _
								'hwnd', $hWnd)   ; handle to window
	Return $aRes[0]

EndFunc

Func GetDlgCtrlID ($hwndCtl)

	Local $aRes = DllCall ($user32dll, 'int', 'GetDlgCtrlID', _
								'hwnd', $hwndCtl)
	Return $aRes[0]

EndFunc

Func GetFocus ( )

	Local $aRes = DllCall ($user32dll, 'hwnd', 'GetFocus')
	Return $aRes[0]

EndFunc

Func GetWindowLongPtr ($hWnd, $nIndex)

	Local $aRes

	If (@OSArch == "X86") Then

		$aRes = DllCall ($user32dll, "LONG", "GetWindowLongW", _
								"HWND", $hWnd, _
								"INT" , $nIndex)
	Else
		$aRes = DllCall ($user32dll, "LONG_PTR", "GetWindowLongPtrW", _
								"HWND", $hWnd, _
								"INT" , $nIndex)
	EndIf

	Return $aRes[0]

EndFunc

Func InflateRect ($lprc, $dx, $dy)

	Local $aRes = DllCall ('user32.dll', 'int', 'InflateRect', _
										'ptr', $lprc, _  ; rectangle
										'int', $dx, _       ; amount to adjust width
										'int', $dy)        ; amount to adjust height
	If @error Then _
		Return @error

	Return $aRes[0]

EndFunc

Func InvalidateRect ($hWnd, $lpRect, $bErase)

	Local $aRes = DllCall ('user32.dll', 'int', 'InvalidateRect', _
										'hwnd', $hWnd, _           ; handle to window
										'ptr', $lpRect, _  ; rectangle coordinates
										'int', $bErase)          ; erase state
	If @error Then _
		Return @error

	Return $aRes[0]

EndFunc

Func ReleaseDC ($hWnd, $hDC)

	Local $aRes = DllCall ($user32dll, 'int', 'ReleaseDC', _
							'hwnd', $hWnd, _  ; handle to window
							'ptr', $hDC)      ; handle to DC
	Return $aRes[0]

EndFunc

Func SelectObject ($hdc, $hgdiobj)

	Local $aRes = DllCall ($gdi32dll, 'ptr', 'SelectObject', _
								'ptr', $hdc, _          ; handle to DC
								'ptr', $hgdiobj)        ; handle to object
	Return $aRes[0]

EndFunc

Func SetWindowLongPtr ($hWnd, $nIndex, $dwNewLong)

	Local $aRes

	If (@OSArch == "X86") Then

		$aRes = DllCall ($user32dll, "LONG", "SetWindowLongW", _
								"HWND", $hWnd, _
								"INT" , $nIndex, _
								"LONG", $dwNewLong)
	Else
		$aRes = DllCall ($user32dll, "LONG_PTR", "SetWindowLongPtrW", _
								"HWND", $hWnd, _
								"INT" , $nIndex, _
								"LONG_PTR", $dwNewLong)
	EndIf

	Return $aRes[0]

EndFunc

Func TrackMouseEvent ($lpEventTrack)

	Local $aRes = DllCall ($user32dll, 'int', 'TrackMouseEvent', _
										'ptr', $lpEventTrack)
	If @error Then _
		Return @error

	Return $aRes[0]

EndFunc

;««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

Func CloseThemeData ($hTheme)

	Local $aRes = DllCall ($uxthemedll, 'long', 'CloseThemeData', _
										'ptr', $hTheme)
	If @error Then _
		Return @error

	Return $aRes[0]

EndFunc

Func OpenThemeData ($hwnd, $pszClassList)

	Local $aRes = DllCall ($uxthemedll, 'ptr', 'OpenThemeData', _
										'hwnd', $hwnd, _
										'wstr', $pszClassList)
	If @error Then _
		Return @error

	Return $aRes[0]

EndFunc

Func DrawThemeBackground ($hTheme, $hdc, $iPartId, $iStateId, $pRect, $pClipRect)

	Local $aRes = DllCall ($uxthemedll, 'long', 'DrawThemeBackground', _
										'ptr', $hTheme, _
										'ptr', $hdc, _
										'int', $iPartId, _
										'int', $iStateId, _
										'ptr', $pRect, _
										'ptr', $pClipRect)
	If @error Then _
		Return @error

	Return $aRes[0]

EndFunc

Func DrawThemeEdge ($hTheme, $hdc, $iPartId, $iStateId, $pDestRect, $uEdge, $uFlags, $pContentRect)

	Local $aRes = DllCall ($uxthemedll, 'long', 'DrawThemeEdge', _
										'ptr', $hTheme, _
										'ptr', $hdc, _
										'int', $iPartId, _
										'int', $iStateId, _
										'ptr', $pDestRect, _
										'uint', $uEdge, _
										'uint', $uFlags, _
										'ptr', $pContentRect)
	If @error Then _
		Return @error

	Return $aRes[0]

EndFunc

Func DrawThemeText ($hTheme, $hdc, $iPartId, $iStateId, $pszText, $iCharCount, $dwTextFlags, $dwTextFlags2, $pRect)

	Local $aRes = DllCall ($uxthemedll, 'long', 'DrawThemeText', _
										'ptr',   $hTheme, _
										'ptr',   $hdc, _
										'int',   $iPartId, _
										'int',   $iStateId, _
										'wstr',  $pszText, _
										'int',   $iCharCount, _
										'dword', $dwTextFlags, _
										'dword', $dwTextFlags2, _
										'ptr',   $pRect)
	If @error Then _
		Return @error

	Return $aRes[0]

EndFunc

Func GetThemeBackgroundContentRect ($hTheme, $hdc, $iPartId, $iStateId, $pBoundingRect, $pContentRect)

	Local $aRes = DllCall ($uxthemedll, 'long', 'GetThemeBackgroundContentRect', _
										'ptr', $hTheme, _
										'ptr', $hdc, _
										'int', $iPartId, _
										'int', $iStateId, _
										'ptr', $pBoundingRect, _
										'ptr', $pContentRect)
	If @error Then _
		Return @error

	Return $aRes[0]

EndFunc

Func GetThemeFont ($hTheme, $hdc, $iPartId, $iStateId, $iPropId, $pFont)

ConsoleWrite ($pFont & @CRLF)

	Local $aRes = DllCall ($uxthemedll, 'long', 'GetThemeFont', _
								'HANDLE', $hTheme, _
								'ptr', $hdc, _
								'int', $iPartId, _
								'int', $iStateId, _
								'int', $iPropId, _
								'ptr', $pFont)
	Return $aRes[0]

EndFunc

Func GetThemeSysFont ($hTheme, $iFontID, $plf)

	Local $aRes = DllCall ($uxthemedll, 'long', 'GetThemeSysFont', _
								'HANDLE', $hTheme, _
								'int', $iFontID, _
								'ptr', $plf)
	Return $aRes[0]

EndFunc

;««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

