#include-once
#include <WinAPIDlg.au3>
#include <WinAPISysWin.au3>

#cs
    -- About --
    GuiCtrlFrame is a collection of label painted as rectangle with specified colour and thickness.
    It is useful, for example, for checking input and immediately highlighting errors by marking the input Ctrl.
    When creating the frame, a map is returned. The IDs of the frame labels are stored there,
    as well as the thickness value and the color values for the frame during creation and for a notification display.

    -- Functions --
    _GuiCtrlFrame_Create        Creates a frame control with specified colour and thickness.
    _GuiCtrlFrame_SetColor      Sets the message color or switches between .color and .colorMsg.
    _GuiCtrlFrame_SetThickness  Sets a new thickness for a frame.
    _GuiCtrlFrame_Show          Shows or hides the frame.
    _GuiCtrlFrame_AssignID      Assign the frame to another Ctrl or the same Ctrl after it has been moved or deletes the frame.
#ce


; #FUNCTION# ====================================================================================================================
; Name ..........: _GuiCtrlFrame_Create
; Description ...: Creates a frame control with specified colour and thickness.
;                  The frame is created at the specified coordinates or around a specified control.
; Syntax ........: _GuiCtrlFrame_Create([$thickness = -1[, $color = -1[, $x = -1[, $y = -1[, $w = -1[, $h = -1]]]]]])
; Parameters ....: $thickness           - [optional] The thickness of the frame lines. Default is -1 (1 px).
; ...............: $color               - [optional] RGB color. Default is -1 (0x0000EE = light dark blue).
; ...............: $x, $y, $w, $h are located within the frame without taking thickness into account.
;                  This allows you to use the same parameters as for Ctrl creation.
; ...............: $x                   - [optional] A variable value. The x-coordinate / a ctrl ID / the most recently created ctrl.
;                                         Default is -1 (the last created ctrl).
; ...............: $y                   - [optional] The y-coordinate. Default is -1 (value from ID).
; ...............: $w                   - [optional] The width value. Default is -1 (value from ID).
; ...............: $h                   - [optional] The height value. Default is -1 (value from ID).
; Return values .: Success	A map containing the IDs for .left, .top, .right, and .bottom label-ctrl of the frame.
;                  			Also .thick, .color and .colorMsg (see function "_GuiCtrlFrame_SetColor")
; ...............: Failure	0 error=1 "-1" passed for $x, but none last created ctrl exists
;                           0 error=2 Detection DlgCtrlID has failed
;                           0 error=3 Not all size parameters have been transferred.
; Author ........: BugFix
; ===============================================================================================================================
Func _GuiCtrlFrame_Create($thickness=-1, $color=-1, $x=-1, $y=-1, $w=-1, $h=-1)
	If $thickness = -1 Then $thickness = 1
	If $color = -1 Then $color = 0x0000EE ; light dark blue
	Local $hLast, $idLast = Null, $hParent, $aCtrl
	If $x = -1 Then	; last created ctrl
		$hLast = GUICtrlGetHandle(-1)
		If $hLast = 0 Then Return SetError(1,0,0)	; none last created ctrl
		$idLast = _WinAPI_GetDlgCtrlID($hLast)
		If $idLast = 0 Then Return SetError(2,0,0)	; detection DlgCtrlID has failed
	Else
		; if has classname, use this ctrl as $idLast - otherwise it's the x-pos
		$hLast = GUICtrlGetHandle($x)
		If _WinAPI_GetClassName($hLast) <> '' Then $idLast = _WinAPI_GetDlgCtrlID($hLast)
	EndIf
	If $idLast <> Null Then
		$hParent = _WinAPI_GetParent($hLast)
		$aCtrl = ControlGetPos($hParent, '', $idLast)
		$x = $aCtrl[0]
		$y = $aCtrl[1]
		$w = $aCtrl[2]
		$h = $aCtrl[3]
	Else	; Check that all size parameters have been transferred.
		If ($y = -1) Or ($w = -1) Or ($h = -1) Then Return SetError(3,0,0)
	EndIf
	Local $mF[]
	$mF.left = GUICtrlCreateLabel(' ', ($x-$thickness), ($y-$thickness), $thickness, ($h+2*$thickness))
	GUICtrlSetBkColor(-1, $color)
	$mF.top = GUICtrlCreateLabel(' ', $x, ($y-$thickness), $w, $thickness)
	GUICtrlSetBkColor(-1, $color)
	$mF.right = GUICtrlCreateLabel(' ', ($x+$w), ($y-$thickness), $thickness, ($h+2*$thickness))
	GUICtrlSetBkColor(-1, $color)
	$mF.bottom = GUICtrlCreateLabel(' ', $x, ($y+$h), $w, $thickness)
	GUICtrlSetBkColor(-1, $color)
	$mF.color = $color
	$mF.colorMsg = 0xEE0000
	$mF.thick = $thickness
	Return $mF
EndFunc



; #FUNCTION# ====================================================================================================================
; Name ..........: _GuiCtrlFrame_SetColor
; Description ...: Sets the message color or switches between .color and .colorMsg.
; Syntax ........: _GuiCtrlFrame_SetColor(ByRef $mFrame[, $colorNew = -1])
; Parameters ....: $mFrame              - The map returned from _GuiCtrlFrame_Create.
; ...............: $colorNew            - [optional] If it is a colour value, it is saved as a the .colorMsg and assigned to the frame.
;                                         "Null" switches back to the frame colour from the creation.
;                                         "-1" (default) assigns the stored .colorMsg to the frame. When starting, "0xEE0000" is stored.
; Return values .: Success	The value of the used color.
;                  Failure  0 @error=1 The parameter 'map' is incorrect.
; Author ........: BugFix
; ===============================================================================================================================
Func _GuiCtrlFrame_SetColor(ByRef $mFrame, $colorNew=-1)
	If Not IsMap($mFrame) Then Return SetError(1, 0, 0)
	Local $color
	If $colorNew = -1 Then
		$color = $mFrame.colorMsg
	Else
		If $colorNew = Null Then
			$color = $mFrame.color
		Else
			$mFrame.colorMsg = $colorNew
			$color = $colorNew
		EndIf
	EndIf
	For $i = $mFrame.left To $mFrame.bottom
		GUICtrlSetBkColor($i, $color)
	Next
	Return '0x' & Hex($color, 6)
EndFunc


; #FUNCTION# ====================================================================================================================
; Name ..........: _GuiCtrlFrame_SetThickness
; Description ...: Sets a new thickness for a frame.
; Syntax ........: _GuiCtrlFrame_SetThickness(ByRef $mFrame[, $thickness = 1])
; Parameters ....: $mFrame              - The map returned from _GuiCtrlFrame_Create.
; ...............: $thickness           - [optional] The new thickness of the frame lines. Default is 1.
; Return values .: Success	1
;                  Failure  0 @error=1 The parameter 'map' is incorrect.
; Author ........: BugFix
; ===============================================================================================================================
Func _GuiCtrlFrame_SetThickness(ByRef $mFrame, $thickness=1)
	If Not IsMap($mFrame) Then Return SetError(1, 0, 0)
    Local $thickOld = $mFrame.thick
    Local $hLast = GUICtrlGetHandle(-1)
    Local $hParent = _WinAPI_GetParent($hLast)
    Local $aPos = ControlGetPos($hParent, '', $mFrame.left)
    GuiCtrlSetPos($mFrame.left, $aPos[0]+$thickOld-$thickness, $aPos[1]+$thickOld-$thickness, $thickness, $aPos[3]-2*$thickOld+2*$thickness)
    $aPos = ControlGetPos($hParent, '', $mFrame.top)
    GuiCtrlSetPos($mFrame.top, $aPos[0], $aPos[1]+$thickOld-$thickness, $aPos[2], $thickness)
    $aPos = ControlGetPos($hParent, '', $mFrame.right)
    GuiCtrlSetPos($mFrame.right, $aPos[0], $aPos[1]+$thickOld-$thickness, $thickness, $aPos[3]-2*$thickOld+2*$thickness)
    $aPos = ControlGetPos($hParent, '', $mFrame.bottom)
    GuiCtrlSetPos($mFrame.bottom, $aPos[0], $aPos[1], $aPos[2], $thickness)
    $mFrame.thick = $thickness
    Return 1
EndFunc


; #FUNCTION# ====================================================================================================================
; Name ..........: _GuiCtrlFrame_Show
; Description ...: Shows or hides the frame.
; Syntax ........: _GuiCtrlFrame_Show(ByRef $mFrame[, $bShow = True])
; Parameters ....: $mFrame              - The map returned from _GuiCtrlFrame_Create.
;                  $bShow               - [optional] A Boolean value that determines whether the frame should be showed or hidden.
;                                         The default value is True=show.
; Return values .: Success	1
;                  Failure  0 @error=1 The parameter 'map' is incorrect.
; Author ........: BugFix
; ===============================================================================================================================
Func _GuiCtrlFrame_Show(ByRef $mFrame, $bShow=True)
	If Not IsMap($mFrame) Then Return SetError(1, 0, 0)
	For $i = $mFrame.left To $mFrame.bottom
		GUICtrlSetState($i, ($bShow ? 16 : 32)) ; 16=$GUI_SHOW, 32=$GUI_HIDE
	Next
	Return 1
EndFunc


; #FUNCTION# ====================================================================================================================
; Name ..........: _GuiCtrlFrame_AssignID
; Description ...: Assign the frame to another Ctrl or the same Ctrl after it has been moved or deletes the frame.
; Syntax ........: _GuiCtrlFrame_AssignID(Byref $mFrame[, $iID = Null])
; Parameters ....: $mFrame              - [in/out] a map.
;                  $iID                 - [optional] an integer value. Default is Null.
; Return values .: Success	1
;                  Failure  0 @error=1 The parameter 'map' is incorrect.
;                             @error=2 The parameter 'ID' is incorrect.
; Author ........: BugFix
; ===============================================================================================================================
Func _GuiCtrlFrame_AssignID(ByRef $mFrame, $iID=Null)
	If Not IsMap($mFrame) Then Return SetError(1, 0, 0)
	For $i = $mFrame.left To $mFrame.bottom
		GUICtrlDelete($i)
	Next
	If $iID = Null Then
		$mFrame = Null
		Return 1
	EndIf
	Local $hID = GUICtrlGetHandle($iID)
	If _WinAPI_GetClassName($hID) = '' Then Return SetError(2, 0, 0)
	Local $mF = _GuiCtrlFrame_Create($mFrame.thick, $mFrame.color, $iID)
	$mF.color = $mFrame.color
	$mF.colorMsg = $mFrame.colorMsg
    $mF.thick = $mFrame.thick
	$mFrame = $mF
	Return 1
EndFunc

