#cs ----------------------------------------------------------------------------

 AutoIt Version: 3.3.8.1
 Author:         Xenon

 Script Function:   Locks the screen, for unlocking a code is needed.

#ce ----------------------------------------------------------------------------


#include <GUIConstantsEx.au3>
#include <StaticConstants.au3>
#include <WindowsConstants.au3>
#include <GDIPlus.au3>
#include <WinAPI.au3>
#include "BlockInputEx.au3"
#include <Misc.au3>
#include <Array.au3>
#include <String.au3>

Global $bEditMode = False
Global $sIniSection = "ScreenLock"
If $CmdLine[0] >= 1 And $CmdLine[1] = "ChangeCode" Then
	$bEditMode = True
	$sIniSection = "ScreenLockSettings"
EndIf

Global $sSettingsIni = @ScriptDir & "\Settings.ini"

Global $nCirclesPerRow = Int(IniRead($sSettingsIni, $sIniSection, "Circles", 3))
Global $nCircles = $nCirclesPerRow*$nCirclesPerRow
Global $nRadius = Int((@DesktopHeight-100)/($nCirclesPerRow+($nCirclesPerRow+1)*0.5))*0.5
Global $aState[$nCircles]
Global $aOrder[$nCircles]
Global $nLastCircle = -1
Global $bRun = True
Global $bCodeRight = True





For $i = 0 To $nCircles-1
	$aOrder[$i] = -1
Next

; Tastatur sperren
If Not $bEditMode Then _BlockInputEx(3)

; GUI erstellen
$hGUI = GUICreate("ScreenLock", @DesktopWidth + 10, @DesktopHeight + 10, -5, -5, $WS_POPUP, $WS_EX_TOPMOST)
GUICtrlCreatePic("",0,0, @DesktopWidth + 10,@DesktopHeight + 10)
; Farbe = schwarz
GUISetBkColor (0x000000, $hGUI)
; Transparenz aus Settings.ini
WinSetTrans ($hGUI, "", IniRead($sSettingsIni, $sIniSection, "Transparency", 125))

; Eingabefeld erstellen
$hChildInput = GUICreate("ScreenLockInput", @DesktopHeight-100, @DesktopHeight - 100, Int((@DesktopWidth-@DesktopHeight+100)*0.5)+10, 100+10, $WS_POPUP,$WS_EX_LAYERED+$WS_EX_MDICHILD+$WS_EX_TOPMOST, $hGUI)
GUISetBkColor(0x050505, $hChildInput)
_WinAPI_SetLayeredWindowAttributes($hChildInput, 0x050505)

; Text-GUI
$hChildCaption = GUICreate("ScreenLockCaption", @DesktopHeight-100, 50, Int((@DesktopWidth-@DesktopHeight+100)*0.5)+10, 25+10, $WS_POPUP,$WS_EX_LAYERED+$WS_EX_MDICHILD+$WS_EX_TOPMOST, $hGUI)
GUISetBkColor(0xABCDEF, $hChildCaption)
$hLabelCaption = GUICtrlCreateLabel("Code eingeben", (@DesktopHeight-219-100)*0.5, 8, 219, 41)
GUICtrlSetFont(-1, 25, 400, 0, "MS Sans Serif")
GUICtrlSetColor(-1, IniRead($sSettingsIni, $sIniSection, "Color", "0x00FF00"))
_WinAPI_SetLayeredWindowAttributes($hChildCaption, 0xABCDEF)

; Alles anzeigen
GUISetState(@SW_SHOW, $hGUI)
GUISetState(@SW_DISABLE, $hGUI)
GUISetState(@SW_SHOW, $hChildInput)
GUISetState(@SW_SHOW, $hChildCaption)

_GDIPlus_Startup()

; Buffer erstellen
$hGraphic =        _GDIPlus_GraphicsCreateFromHWND($hChildInput)
$hBitmap =         _GDIPlus_BitmapCreateFromGraphics(@DesktopHeight-100, @DesktopHeight-100, $hGraphic)
$hBuffer =         _GDIPlus_ImageGetGraphicsContext($hBitmap)
_GDIPlus_GraphicsSetSmoothingMode ($hBuffer, 2)
_GDIPlus_GraphicsSetSmoothingMode ($hGraphic, 2)

; Brushs und Pens erstellen
$hBrushActivated =			_GDIPlus_BrushCreateSolid (Dec("FF" & StringReplace(IniRead($sSettingsIni, $sIniSection, "Color", "0x00FF00"), "0x", "")))
$hBrushInvisible = 			_GDIPlus_BrushCreateSolid (0xFF050505)
$hBrushRed =       			_GDIPlus_BrushCreateSolid (0xFFFF0000)
$hBrushWhite =     			_GDIPlus_BrushCreateSolid (0xFFFFFFFF)
$hPenActivated =    		_GDIPlus_PenCreate (Dec("FF" & StringReplace(IniRead($sSettingsIni, $sIniSection, "Color", "0x00FF00"), "0x", "")), 6, 2)
$hPenRed =    				_GDIPlus_PenCreate (0xFFFF0000, 6, 2)
$hPenBlack =    			_GDIPlus_PenCreate (0xFF000000, 12, 2)

; Alles zeichnen
_Render ()


; Dauerschleife
While $bRun


	; Andere Fenster in den Hintergrund
	If Not WinActive ("ScreenLockInput") And Not $bEditMode Then
		WinActivate ("ScreenLockInput")
	EndIf

	; Überprüfen, ob linke Maustaste noch gedrückt, wenn ja, Abstand zu allen Kreisen berechen:
	$aCursorInfo = GUIGetCursorInfo ($hChildInput)
	If $aCursorInfo[2] Then
		$MousePosition = MouseGetPos ()
		For $i = 0 To $nCirclesPerRow-1			; Alle Kreise durchlaufen
			For $j = 0 To $nCirclesPerRow-1
				If Sqrt (($MousePosition[0] - ($i *$nRadius*3+2*$nRadius + Int((@DesktopWidth-@DesktopHeight+100)*0.5)))*($MousePosition[0] - ($i *$nRadius*3+2*$nRadius + Int((@DesktopWidth-@DesktopHeight+100)*0.5))) + _
						 ($MousePosition[1] - ($j *$nRadius*3+2*$nRadius + 100)) * ($MousePosition[1] - ($j *$nRadius*3+2*$nRadius + 100)))   <= $nRadius Then  ;Abstand nach Pythagoras

					$aState[$i*$nCirclesPerRow+$j] = 1
					If $nLastCircle <= $nCircles-1 And _ArraySearch ($aOrder, $i * $nCirclesPerRow + $j) = -1 Then
						$nLastCircle += 1
						$aOrder[$nLastCircle] = $i * $nCirclesPerRow + $j
						_Render ()
					EndIf

					If $nLastCircle >= $nCircles-1 And Not _CheckCode () Then
						_Render (True)
						Sleep (1500)
						For $i = 0 To $nCircles-1
							$aOrder[$i] = -1
							$aState[$i] = 0
						Next
						$nLastCircle = -1
						_Render ()
					EndIf
				EndIf
			Next
		Next
	Else
		If $aOrder[0] <> -1 And Not _CheckCode () Then
				_Render (True)
				Sleep (1500)
				For $i = 0 To $nCircles-1
					$aOrder[$i] = -1
					$aState[$i] = 0
				Next
				$nLastCircle = -1
				_Render ()
			EndIf
	EndIf
WEnd

; Ressourcen freigeben
_GDIPlus_PenDispose     ($hPenActivated)
_GDIPlus_PenDispose     ($hPenRed)
_GDIPlus_PenDispose     ($hPenBlack)
_GDIPlus_BitmapDispose  ($hBitmap)
_GDIPlus_BrushDispose   ($hBrushActivated)
_GDIPlus_BrushDispose   ($hBrushInvisible)
_GDIPlus_BrushDispose   ($hBrushRed)
_GDIPlus_BrushDispose   ($hBrushWhite)
_GDIPlus_GraphicsDispose($hGraphic)

_GDIPlus_Shutdown()

If Not $bEditMode Then _BlockInputEx (0) ; Tastatur entsperren



Func _CreateCircle ($nColor, $nCenterX, $nCenterY) ; $nColor - Farbe (0-weiß, 1-aktive Farbe, 2-Fehler)  ;  $nCenterX/Y  - Mittelpunkt des zu zeichnenden Kreises (Koordinaten)
	Local $nWidth1 = 10
	Local $nWidth2 = 20
	Local $nWidth3 = 60
	Local $hBrush
	If $nColor = 0 Then
		$hBrush = _GDIPlus_BrushClone ($hBrushWhite)
	ElseIf $nColor = 1 Then
		$hBrush = _GDIPlus_BrushClone ($hBrushActivated)
	ElseIf $nColor = 2 Then
		$hBrush = _GDIPlus_BrushClone ($hBrushRed)
	EndIf
	_GDIPlus_GraphicsFillEllipse($hBuffer, $nCenterX - $nRadius                  , $nCenterY - $nRadius                  , 2*$nRadius                  , 2*$nRadius)
	_GDIPlus_GraphicsFillEllipse($hBuffer, $nCenterX - $nRadius + Round($nRadius/100*$nWidth1), $nCenterY - $nRadius + Round($nRadius/100*$nWidth1), 2*$nRadius - Round($nRadius/100*2*$nWidth1), 2*$nRadius - Round($nRadius/100*2*$nWidth1), $hBrush)
	_GDIPlus_GraphicsFillEllipse($hBuffer, $nCenterX - $nRadius + Round($nRadius/100*$nWidth2), $nCenterY - $nRadius + Round($nRadius/100*$nWidth2), 2*$nRadius - Round($nRadius/100*2*$nWidth2), 2*$nRadius - Round($nRadius/100*2*$nWidth2))
	_GDIPlus_GraphicsFillEllipse($hBuffer, $nCenterX - $nRadius + Round($nRadius/100*$nWidth3), $nCenterY - $nRadius + Round($nRadius/100*$nWidth3), 2*$nRadius - Round($nRadius/100*2*$nWidth3), 2*$nRadius - Round($nRadius/100*2*$nWidth3), $hBrush)
	_GDIPlus_BrushDispose ($hBrush)
EndFunc ; _CreateCircle ($nColor, $nCenterX, $nCenterY)

Func _Render ($bWrongCode = False) ; $bWrongCode - Falscher Code eingegeben? (standart: nein)

	; unsichtbarer Hintergrund
	_GDIPlus_GraphicsFillRect ($hBuffer, -1, -1, @DesktopWidth+2, @DesktopWidth+98, $hBrushInvisible)

	If Not $bWrongCode Then

		; kein falscher Code -> Standardfarben
		If Not $bCodeRight Then
			GUICtrlSetData ($hLabelCaption, "Code eingeben")
			GUICtrlSetColor($hLabelCaption, IniRead($sSettingsIni, "ScreenLock", "Color", "0x00FF00"))
			$bCodeRight = True
		EndIf

		; alle Linien zeichnen
		For $i = 1 To $nCircles-1
			If $aOrder[$i] = -1 Then ExitLoop
			_GDIPlus_GraphicsDrawLine ($hBuffer, Int($aOrder[$i-1]/$nCirclesPerRow) *$nRadius*3+2*$nRadius, Mod($aOrder[$i-1], $nCirclesPerRow)*$nRadius*3+2*$nRadius, Int($aOrder[$i]/$nCirclesPerRow) *$nRadius*3+2*$nRadius, Mod($aOrder[$i], $nCirclesPerRow)*$nRadius*3+2*$nRadius, $hPenBlack)
			_GDIPlus_GraphicsDrawLine ($hBuffer, Int($aOrder[$i-1]/$nCirclesPerRow) *$nRadius*3+2*$nRadius, Mod($aOrder[$i-1], $nCirclesPerRow)*$nRadius*3+2*$nRadius, Int($aOrder[$i]/$nCirclesPerRow) *$nRadius*3+2*$nRadius, Mod($aOrder[$i], $nCirclesPerRow)*$nRadius*3+2*$nRadius, $hPenActivated)
		Next

		;Kreise erstellen
		For $i = 0 To $nCirclesPerRow-1
			For $j = 0 To $nCirclesPerRow-1
				_CreateCircle ($aState[$i*$nCirclesPerRow+$j], $i*$nRadius*3+2*$nRadius, $j*$nRadius*3+2*$nRadius)
			Next
		Next


	Else
		; falscher Code -> rote Farbe

		If $bCodeRight Then
			GUICtrlSetData ($hLabelCaption, "Falscher Code")
			GUICtrlSetColor($hLabelCaption, 0xFF0000)
			$bCodeRight = False
		EndIf

		; alle Linien zeichnen
		For $i = 1 To $nCircles-1
			If $aOrder[$i] = -1 Then ExitLoop
			_GDIPlus_GraphicsDrawLine ($hBuffer, Int($aOrder[$i-1]/$nCirclesPerRow) *$nRadius*3+2*$nRadius, Mod($aOrder[$i-1], $nCirclesPerRow)*$nRadius*3+2*$nRadius, Int($aOrder[$i]/$nCirclesPerRow)*$nRadius*3+2*$nRadius, Mod($aOrder[$i], $nCirclesPerRow)*$nRadius*3+2*$nRadius, $hPenBlack)
			_GDIPlus_GraphicsDrawLine ($hBuffer, Int($aOrder[$i-1]/$nCirclesPerRow) *$nRadius*3+2*$nRadius, Mod($aOrder[$i-1], $nCirclesPerRow)*$nRadius*3+2*$nRadius, Int($aOrder[$i]/$nCirclesPerRow)*$nRadius*3+2*$nRadius, Mod($aOrder[$i], $nCirclesPerRow)*$nRadius*3+2*$nRadius, $hPenRed)
		Next

		;Kreise erstellen
		For $i = 0 To $nCirclesPerRow-1
			For $j = 0 To $nCirclesPerRow-1
				_CreateCircle (2, $i*$nRadius*3+2*$nRadius, $j*$nRadius*3+2*$nRadius)
			Next
		Next
	EndIf


	; alles auf GUI anzeigen
	_GDIPlus_GraphicsDrawImageRect($hGraphic, $hBitmap, 0, 0, @DesktopHeight-100, @DesktopHeight-100)

EndFunc

Func _CheckCode ()
	Local $sCode = ""

	; Code entsteht aus zusammensetzen der Reihenfolge zu einem String
	For $i = 0 To $nCircles-1
		If $aOrder[$i] <> -1 Then
			$sCode &= $aOrder[$i]
		Else
			ExitLoop
		EndIf

	Next

	If Not $bEditMode Then
		; Wenn .ini-Code leer oder gleich dem Eingegebenen, dann Programm beenden
		If IniRead ($sSettingsIni, "ScreenLock", "Code", "") = "" Or IniRead ($sSettingsIni, "ScreenLock", "Code", "") == _StringEncrypt (1, $sCode, $sCode, 3) Then
			$bRun = False
			Return True ;richtiger Code
		EndIf
		Return False ;falscher Code
	Else
		IniWrite ($sSettingsIni, $sIniSection, "Code", _StringEncrypt (1, $sCode, $sCode, 3))
		$bRun = False
		Return True
	EndIf

EndFunc