; 12 / 2011 von BLinz - www.autoit.de
#include <Array.au3>
#include <GUIConstantsEx.au3>
#include <SliderConstants.au3>
#include <StaticConstants.au3>
#include <WindowsConstants.au3>

Global $aScreenDimension ; Hier kommen die Gesamtmaße (Gesamtbreite / Höhe) der Monitore rein zwecks Maßstabsbrechnung
Global $aAllScreenswithDimensions ; Hier stehen Anzahl, Position und Maße aller Monitore drin
Global $iResizeFaktor ; Um welchen Faktor müssen wir verkleinern beim Zeichnen
Global $iZeroPointX, $iZeroPointY ; Wohin mit dem Nullpunkt auf unserer Zeichenfläche (wegen Negativen Koordinaten)
Global $LabelMonitors[1] ; Zeiger auf die Label die die Monitore darstellen
Global $aUseableMonitorMargins[1][4] ; Hier kommt für jede der 4 Seiten eine Monitors ein Wert rein
									 ; ob diese Frei ist (True) oder an einen anderen angrenzt (False)
Global $ButtonMargins[1] ; Die Ränder werden mit Buttons dargestellt, hier die Zeiger dafür
Global $iDrawingSize = 300 ; Grundwert, Größe der Zeichenfläche, kann per Slider angepasst werden
Global $iOldSliderValue ; Für Echtzeitvorschau wenn der Slider bewegt wird
Global $bShowMargins = False ; Grundwert, nicht die Ränder zeigen an denen ein Slider Fenster hin könnte

;Wieder kleine GUI mit Koda ...
#Region ### START Koda GUI section ### Form=c:\_autoit\z-slider\displaymonitorconfiguration.kxf
$FormDisplayMonitorConfiguration = GUICreate("DisplayMonitorConfigurationDEMO", 615, 601, 409, 137)
$Slider1 = GUICtrlCreateSlider(56, 496, 500, 45, BitOR($GUI_SS_DEFAULT_SLIDER,$TBS_TOP,$TBS_LEFT,$TBS_ENABLESELRANGE))
$Label1 = GUICtrlCreateLabel("100px", 56, 480, 33, 17)
$Label2 = GUICtrlCreateLabel("600px", 528, 480, 33, 17)
$CheckboxShowPossibleSlider = GUICtrlCreateCheckbox("Zeige mögliche Positionen für ein Slider Fenster", 64, 544, 481, 17)
$ButtonMonArray = GUICtrlCreateButton("Zeige Monitore-Array", 64, 568, 130, 25)
$ButtonMarginArray = GUICtrlCreateButton("Zeige freie Seiten Array", 336, 568, 130, 25)
$ButtonScreenDims = GUICtrlCreateButton("Zeige BildschirmDims", 200, 568, 130, 25)
GUISetState(@SW_SHOW)
#EndRegion ### END Koda GUI section ###

;Slider auf Startwert setzen
GUICtrlSetData($Slider1, ($iDrawingSize - 100) / 5)
$iOldSliderValue = GUICtrlRead($Slider1)

;Gesamte Bildschrimausmaße über alle Monitore ermitteln,
; Ergibt auch bei Monitoren mit negativen Koordinaten die Gesamtbreite / -höhe
$aScreenDimension = WinGetPos("Program Manager")
	;$aScreenDimension[0] = X-Position
	;$aScreenDimension[1] = Y-Position
	;$aScreenDimension[2] = Breite
	;$aScreenDimension[3] = Höhe

;_ArrayDisplay($aScreenDimension)

;Umrechnungsfaktor für unsere (momentan 300 x 300) Fläche ermitteln
If $aScreenDimension[2] > $aScreenDimension[3] Then
	$iResizeFaktor = $iDrawingSize / $aScreenDimension[2]
Else
	$iResizeFaktor = $iDrawingSize / $aScreenDimension[3] ;
EndIf

;Nullpunkte für unsere (momentan noch 300 x 300) Fläche ermitteln
;    0       =       300       -    300        /        (  3600            /     ( 0             + 3600))
;   140        =       300       -    300        /        (  3600            /     ( -1680         + 3600))
$iZeroPointX = $iDrawingSize - ($iDrawingSize / ($aScreenDimension[2] / ($aScreenDimension[0] + $aScreenDimension[2])))
;Nun kann es sein das ein negativer Wert herauskommt - dann in positiv wandeln
If $iZeroPointX < 0 Then $iZeroPointX = $iZeroPointX * (-1)
;Das selbe noch einmal für Y Achse
$iZeroPointY = $iDrawingSize - ($iDrawingSize / ($aScreenDimension[3] / ($aScreenDimension[1] + $aScreenDimension[3])))
If $iZeroPointY < 0 Then $iZeroPointX = $iZeroPointY * (-1)

; Anzahl und Auflösung der einzelnen Monitore holen
$aAllScreenswithDimensions = _GetMonitors()
;	$aAllScreenswithDimensions[0][0] with number of Monitors,
;   $aAllScreenswithDimensions[x][0] Monitor X Screen wide
;   $aAllScreenswithDimensions[x][1] Monitor X Screen height
;   $aAllScreenswithDimensions[x][2] Monitor X Screen Position X
;   $aAllScreenswithDimensions[x][3] Monitor X Screen Position Y

; Ermitteln an welchen Rändern die Monitore "zusammenstoßen" bzw. verbunden sind
Redim $aUseableMonitorMargins[$aAllScreenswithDimensions[0][0] + 1][4]
$aUseableMonitorMargins[0][0] = "Links"
$aUseableMonitorMargins[0][1] = "Rechts"
$aUseableMonitorMargins[0][2] = "Oben"
$aUseableMonitorMargins[0][3] = "Unten"
	; $aUseableMonitorMargins[x][0] = Left Margin
	; $aUseableMonitorMargins[x][1] = Right Margin
	; $aUseableMonitorMargins[x][2] = Top Margin
	; $aUseableMonitorMargins[x][3] = Bottom Margin

; Ermittel welcher Monitor wo steht und an welchen Seiten diese aneinander stoßen
_GetMonitorMargins()

;Die Monitore stellen wir durch Labels dar - Anzahl dimensonieren
ReDim $LabelMonitors[$aAllScreenswithDimensions[0][0] + 1]
$LabelMonitors[0] = $aAllScreenswithDimensions[0][0]
;Die freien Ränder durch Buttons - einfach Monitore * 4 - sind zwar bestimmt zuviel aber nie zuwenig
Redim $ButtonMargins[$aAllScreenswithDimensions[0][0] * 4]

;Monitore zeichnen
_DrawMonitors()

;Hauptschleife zur Abfrage der GUI
While 1
	$nMsg = GUIGetMsg()
	Switch $nMsg
		Case $GUI_EVENT_CLOSE
			Exit
		Case $CheckboxShowPossibleSlider
			;Ok, jemand will die freien Seiten sehen (oder nicht mehr sehen)
			If BitAnd(GUICtrlRead($CheckboxShowPossibleSlider),$GUI_CHECKED) = $GUI_CHECKED Then
				$bShowMargins = True ; Anzeigen
			Else
				$bShowMargins = False ; Nicht anzeigen
			EndIf
			;Einmal alles neu Zeichnen lassen
			_DeleteMonitors()
			_DrawMonitors()
		Case $ButtonMonArray
			_ArrayDisplay($aAllScreenswithDimensions)
		Case $ButtonMarginArray
			_ArrayDisplay($aUseableMonitorMargins)
		case $ButtonScreenDims
			_ArrayDisplay($aScreenDimension)
	EndSwitch
	;Echtzeitvorschau des Sliders, neu zeichnen wenn der Wert sich ändert
	If $iOldSliderValue <> GUICtrlRead($Slider1) Then
		$iDrawingSize = (GUICtrlRead($Slider1) * 5) + 100 ;Slider ist von 0 bis 100, Werte aber von 100 bis 600
		; Verkleinerungsfaktor neu ausrechnen
		If $aScreenDimension[2] > $aScreenDimension[3] Then
			$iResizeFaktor = $iDrawingSize / $aScreenDimension[2]
		Else
			$iResizeFaktor = $iDrawingSize / $aScreenDimension[3]
		EndIf
		$iOldSliderValue = GUICtrlRead($Slider1)
		$iZeroPointX = $iDrawingSize - ($iDrawingSize / ($aScreenDimension[2] / ($aScreenDimension[0] + $aScreenDimension[2])))
		If $iZeroPointX < 0 Then $iZeroPointX = $iZeroPointX * (-1)
		$iZeroPointY = $iDrawingSize - ($iDrawingSize / ($aScreenDimension[3] / ($aScreenDimension[1] + $aScreenDimension[3])))
		If $iZeroPointY < 0 Then $iZeroPointX = $iZeroPointY * (-1)
		_DeleteMonitors()
		_DrawMonitors()
	EndIf
WEnd


;löscht alle gezeichten Labels und Buttons
Func _DeleteMonitors()
	For $i = 1 To $LabelMonitors[0]
		GUICtrlDelete($LabelMonitors[$i])
	Next
	For $i = 0 To UBound($ButtonMargins) - 1
		GUICtrlDelete($ButtonMargins[$i])
	Next
EndFunc

;Zeichnet die Monitore und ggf. Buttons Maßstabsgerecht
;	$aAllScreenswithDimensions[0][0] with number of Monitors,
;   $aAllScreenswithDimensions[x][0] Monitor X Screen wide
;   $aAllScreenswithDimensions[x][1] Monitor X Screen height
;   $aAllScreenswithDimensions[x][2] Monitor X Screen Position X
;   $aAllScreenswithDimensions[x][3] Monitor X Screen Position Y
Func _DrawMonitors()
	Local $j = 0
	For $i = 1 To $LabelMonitors[0]
		$LabelMonitors[$i] = GUICtrlCreateLabel($i, 	16 + $iZeroPointX + Floor($aAllScreenswithDimensions[$i][2] * $iResizeFaktor), _
														16 + $iZeroPointY + Floor($aAllScreenswithDimensions[$i][3] * $iResizeFaktor), _
														Floor($aAllScreenswithDimensions[$i][0] * $iResizeFaktor), _
														Floor($aAllScreenswithDimensions[$i][1] * $iResizeFaktor), _
														BitOR($SS_CENTER,$SS_CENTERIMAGE,$WS_BORDER))
		GUICtrlSetFont($LabelMonitors[$i], 14, 800, 0, "Courier New")
		GUICtrlSetBkColor($LabelMonitors[$i], 0xffffff)
		; $aUseableMonitorMargins[x][0] = Left Margin
		; $aUseableMonitorMargins[x][1] = Right Margin
		; $aUseableMonitorMargins[x][2] = Top Margin
		; $aUseableMonitorMargins[x][3] = Bottom Margin
		If $bShowMargins = True Then
			; links Button setzen bei Bedarf
			If $aUseableMonitorMargins[$i][0] = True Then
				$ButtonMargins[$j] = GUICtrlCreateButton("", 16 + $iZeroPointX + Floor($aAllScreenswithDimensions[$i][2] * $iResizeFaktor), _
															16 + $iZeroPointY + Floor($aAllScreenswithDimensions[$i][3] * $iResizeFaktor), _
															12, _
															Floor($aAllScreenswithDimensions[$i][1] * $iResizeFaktor))
				GUICtrlSetBkColor($ButtonMargins[$j], 0x00ff00)
				$j = $j + 1
			EndIf
			; rechts Button setzen bei Bedarf
			If $aUseableMonitorMargins[$i][1] = True Then
				$ButtonMargins[$j] = GUICtrlCreateButton("", 4 + $iZeroPointX + Floor(($aAllScreenswithDimensions[$i][2] + $aAllScreenswithDimensions[$i][0]) * $iResizeFaktor), _
															16 + $iZeroPointY + Floor($aAllScreenswithDimensions[$i][3] * $iResizeFaktor), _
															12, _
															Floor($aAllScreenswithDimensions[$i][1] * $iResizeFaktor))
				GUICtrlSetBkColor($ButtonMargins[$j], 0x00ff00)
				$j = $j + 1
			EndIf
			; oben setzen bei Bedarf
			If $aUseableMonitorMargins[$i][2] = True Then
				$ButtonMargins[$j] = GUICtrlCreateButton("", 16 + $iZeroPointX + Floor($aAllScreenswithDimensions[$i][2] * $iResizeFaktor), _
															16 + $iZeroPointY + Floor($aAllScreenswithDimensions[$i][3] * $iResizeFaktor), _
															Floor($aAllScreenswithDimensions[$i][0] * $iResizeFaktor), _
															12)
				GUICtrlSetBkColor($ButtonMargins[$j], 0x00ff00)
				$j = $j + 1
			EndIf
			; unten setzen bei Bedarf
			If $aUseableMonitorMargins[$i][3] = True Then
				$ButtonMargins[$j] = GUICtrlCreateButton("", 16 + $iZeroPointX + Floor($aAllScreenswithDimensions[$i][2] * $iResizeFaktor), _
															4 + $iZeroPointY + Floor(($aAllScreenswithDimensions[$i][3] + $aAllScreenswithDimensions[$i][1]) * $iResizeFaktor), _
															Floor($aAllScreenswithDimensions[$i][0] * $iResizeFaktor), _
															12)
				GUICtrlSetBkColor($ButtonMargins[$j], 0x00ff00)
				$j = $j + 1
			EndIf
		EndIf
	Next
EndFunc


;Findet heraus welcher Monitor mit welcher Seite an welchen anderen Monitor stößt
; True = Seite Frei
; False = Da ist ein anderer Monitor
; $aUseableMonitorMargins[x][0] = Left Margin
; $aUseableMonitorMargins[x][1] = Right Margin
; $aUseableMonitorMargins[x][2] = Top Margin
; $aUseableMonitorMargins[x][3] = Bottom Margin
Func _GetMonitorMargins()
	; Alles auf True setzen (=Seite ist frei)
	For $i = 1 To $aAllScreenswithDimensions[0][0]
		For $j = 0 To 3
			$aUseableMonitorMargins[$i][$j] = True
		Next
	Next
	;Jetzt die auf False setzen die an einen anderen Monitor stoßen (Testen immer 10 Pixel in die Richtung, daher +/- 10)
	;Wir prüfen vom Mittelpunkt einen Monitors mit +/- 200 Pixel Toleranz nach oben/unten oder links/rechts
	For $i = 1 To $aAllScreenswithDimensions[0][0]
		For $j = 1 To $aAllScreenswithDimensions[0][0]
			If $i <> $j Then ; gegen sich selbst müssen wir nicht prüfen
				; Horizontale Prüfungen - ausgehend von der vertikalen Mitte ( /2 ) , Toleranz 200 Pixel nach oben oder unten ( + oder - 200)
				If $aAllScreenswithDimensions[$i][3] < ($aAllScreenswithDimensions[$j][3] + ($aAllScreenswithDimensions[$j][1] / 2) - 200) And _
					($aAllScreenswithDimensions[$i][3] + $aAllScreenswithDimensions[$i][1]) > ($aAllScreenswithDimensions[$j][3] + ($aAllScreenswithDimensions[$j][1] / 2) + 200) Then
					; Ist neben dem linken Rand etwas?
					If ($aAllScreenswithDimensions[$i][2] - 10) < ($aAllScreenswithDimensions[$j][2] + $aAllScreenswithDimensions[$j][0]) And _
						($aAllScreenswithDimensions[$i][2] - 10) > $aAllScreenswithDimensions[$j][2] Then
						$aUseableMonitorMargins[$i][0] = False
						$aUseableMonitorMargins[$j][1] = False
					EndIf
					; Ist neben dem rechten Rand etwas?
					If ($aAllScreenswithDimensions[$i][2] + $aAllScreenswithDimensions[$i][0] + 10) > $aAllScreenswithDimensions[$j][2] And _
						($aAllScreenswithDimensions[$i][2] + $aAllScreenswithDimensions[$i][0] + 10) < ($aAllScreenswithDimensions[$j][2] + $aAllScreenswithDimensions[$j][0]) Then
						$aUseableMonitorMargins[$i][1] = False
						$aUseableMonitorMargins[$j][0] = False
					EndIf
				EndIf
				; Vertikale Prüfungen - ausgehend von der horizontalen Mitte ( /2), Toleranz 200 Pixel nach links oder rechts ( + oder - 200)
				If $aAllScreenswithDimensions[$i][2] < ($aAllScreenswithDimensions[$j][2] + ($aAllScreenswithDimensions[$j][0] / 2) - 200) And _
					($aAllScreenswithDimensions[$i][2] + $aAllScreenswithDimensions[$i][0]) > ($aAllScreenswithDimensions[$j][2] + ($aAllScreenswithDimensions[$j][0] / 2) + 200) Then
					; Ist oben etwas?
					If ($aAllScreenswithDimensions[$i][3] - 10) < ($aAllScreenswithDimensions[$j][3] + $aAllScreenswithDimensions[$j][1]) And _
						($aAllScreenswithDimensions[$i][3] - 10) > $aAllScreenswithDimensions[$j][3] Then
						$aUseableMonitorMargins[$i][2] = False
						$aUseableMonitorMargins[$j][3] = False
					EndIf
					; Ist unten etwas?
					If ($aAllScreenswithDimensions[$i][3] + $aAllScreenswithDimensions[$i][1] + 10) > $aAllScreenswithDimensions[$j][3] And _
						($aAllScreenswithDimensions[$i][3] + $aAllScreenswithDimensions[$i][1] + 10) < ($aAllScreenswithDimensions[$j][3] + $aAllScreenswithDimensions[$j][1]) Then
						$aUseableMonitorMargins[$i][3] = False
						$aUseableMonitorMargins[$j][2] = False
					EndIf
				EndIf
			EndIf
		Next
	Next
EndFunc




; #FUNCTION# ====================================================================================================================
; Name ..........: _GetMonitors
; Description ...:
; Syntax ........: _GetMonitors()
; Parameters ....:
; Return values .: Array[0][0] with number of Monitors,
;                  Array[x][0] Monitor X Screen wide
;                  Array[x][1] Monitor X Screen height
;                  Array[x][2] Monitor X Screen Position X
;                  Array[x][3] Monitor X Screen Position Y
; Author ........: AspirinJunkie
; Modified ......:
; Remarks .......:
; Related .......:
; Link ..........: http://autoit.de/index.php?page=Thread&postID=101717#post101717
; Example .......: No
; ===============================================================================================================================
Func _GetMonitors()
    Local $cbMonitorEnumProc = DllCallbackRegister("MonitorEnumProc", "ubyte", "ptr;ptr;ptr;int")
    If @error Then Return SetError(1, 0, False)
    Local $strctCount = DllStructCreate("uint Count;uint Width[12];uint Height[12];int left[12];int top[12]")
    If @error Then Return SetError(2, @error, False)
    Local $iCount

    DllStructSetData($strctCount, "Count", 0)

    $Ret = DllCall("User32.dll", "ubyte","EnumDisplayMonitors","ptr", 0,"ptr", 0, "ptr", DllCallbackGetPtr($cbMonitorEnumProc), "ptr", DllStructGetPtr($strctCount))
    If @error Or $Ret[0] = 0 Then Return SetError(3, @error, False)

    DllCallbackFree($cbMonitorEnumProc)

    $iCount = Int(DllStructGetData($strctCount, "Count"))

    Local $aMonitors[$iCount+1][4] = [[$iCount]]

    For $i = 1 To $iCount
        $aMonitors[$i][0] = Int(DllStructGetData($strctCount, "Width",$i))
        $aMonitors[$i][1] = Int(DllStructGetData($strctCount, "Height",$i))
        $aMonitors[$i][2] = Int(DllStructGetData($strctCount, "left",$i))
        $aMonitors[$i][3] = Int(DllStructGetData($strctCount, "top",$i))
    Next

    Return $aMonitors
EndFunc
Func MonitorEnumProc($hMonitor, $hdcMonitor, $lprcMonitor, $dwData)
    Local $strctRECT = DllStructCreate("long left;long top;long right;long bottom", $lprcMonitor)
    Local $strctCount = DllStructCreate("uint Count;uint Width[12];uint Height[12];int left[12];int top[12]", $dwData)
    Local $iNumber = DllStructGetData($strctCount, "Count")
    Local $Height = Int(DllStructGetData($strctRECT, "bottom"))-Int(DllStructGetData($strctRECT, "top"))
    Local $Width = Int(DllStructGetData($strctRECT, "right"))-Int(DllStructGetData($strctRECT, "left"))

    DllStructSetData($strctCount, "Width", $Width, $iNumber+1)
    DllStructSetData($strctCount, "Height", $Height, $iNumber+1)
    DllStructSetData($strctCount, "left", Int(DllStructGetData($strctRECT, "left")), $iNumber+1)
    DllStructSetData($strctCount, "top", Int(DllStructGetData($strctRECT, "top")), $iNumber+1)
    DllStructSetData($strctCount, "Count", $iNumber+1)
    Return True
EndFunc
; ===============================================================================================================================
