280 lines
14 KiB
AutoIt
280 lines
14 KiB
AutoIt
|
#include-once
|
||
|
|
||
|
; #INDEX# ============================================================================================================
|
||
|
; Title .........: _StringSize
|
||
|
; AutoIt Version : v3.2.12.1 or higher
|
||
|
; Language ......: English
|
||
|
; Description ...: Returns size of rectangle required to display string - maximum width can be chosen
|
||
|
; Remarks .......:
|
||
|
; Note ..........:
|
||
|
; Author(s) .....: Melba23 - thanks to trancexx for the default DC code
|
||
|
; ====================================================================================================================
|
||
|
|
||
|
;#AutoIt3Wrapper_Au3Check_Parameters=-d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6
|
||
|
|
||
|
; #CURRENT# ==========================================================================================================
|
||
|
; _StringSize: Returns size of rectangle required to display string - maximum width can be chosen
|
||
|
; ====================================================================================================================
|
||
|
|
||
|
; #INTERNAL_USE_ONLY#=================================================================================================
|
||
|
; _StringSize_Error_Close: Releases DC and deletes font object after error
|
||
|
; _StringSize_DefaultFontName: Determines Windows default font
|
||
|
; ====================================================================================================================
|
||
|
|
||
|
; #FUNCTION# =========================================================================================================
|
||
|
; Name...........: _StringSize
|
||
|
; Description ...: Returns size of rectangle required to display string - maximum permitted width can be chosen
|
||
|
; Syntax ........: _StringSize($sText[, $iSize[, $iWeight[, $iAttrib[, $sName[, $iWidth[, $hWnd]]]]]])
|
||
|
; Parameters ....: $sText - String to display
|
||
|
; $iSize - [optional] Font size in points - (default = 8.5)
|
||
|
; $iWeight - [optional] Font weight - (default = 400 = normal)
|
||
|
; $iAttrib - [optional] Font attribute (0-Normal (default), 2-Italic, 4-Underline, 8 Strike)
|
||
|
; + 1 if tabs are to be expanded before sizing
|
||
|
; $sName - [optional] Font name - (default = Tahoma)
|
||
|
; $iWidth - [optional] Max width for rectangle - (default = 0 => width of original string)
|
||
|
; $hWnd - [optional] GUI in which string will be displayed - (default 0 => normally not required)
|
||
|
; Requirement(s) : v3.2.12.1 or higher
|
||
|
; Return values .: Success - Returns 4-element array: ($iWidth set // $iWidth not set)
|
||
|
; |$array[0] = String reformatted with additonal @CRLF // Original string
|
||
|
; |$array[1] = Height of single line in selected font // idem
|
||
|
; |$array[2] = Width of rectangle required for reformatted // original string
|
||
|
; |$array[3] = Height of rectangle required for reformatted // original string
|
||
|
; Failure - Returns 0 and sets @error:
|
||
|
; |1 - Incorrect parameter type (@extended = parameter index)
|
||
|
; |2 - DLL call error - extended set as follows:
|
||
|
; |1 - GetDC failure
|
||
|
; |2 - SendMessage failure
|
||
|
; |3 - GetDeviceCaps failure
|
||
|
; |4 - CreateFont failure
|
||
|
; |5 - SelectObject failure
|
||
|
; |6 - GetTextExtentPoint32 failure
|
||
|
; |3 - Font too large for chosen max width - a word will not fit
|
||
|
; Author ........: Melba23 - thanks to trancexx for the default DC code
|
||
|
; Modified ......:
|
||
|
; Remarks .......: The use of the $hWnd parameter is not normally necessary - it is only required if the UDF does not
|
||
|
; return correct dimensions without it.
|
||
|
; Related .......:
|
||
|
; Link ..........:
|
||
|
; Example .......: Yes
|
||
|
;=====================================================================================================================
|
||
|
Func _StringSize($sText, $iSize = 8.5, $iWeight = 400, $iAttrib = 0, $sName = "", $iMaxWidth = 0, $hWnd = 0)
|
||
|
|
||
|
; Set parameters passed as Default
|
||
|
If $iSize = Default Then $iSize = 8.5
|
||
|
If $iWeight = Default Then $iWeight = 400
|
||
|
If $iAttrib = Default Then $iAttrib = 0
|
||
|
If $sName = "" Or $sName = Default Then $sName = _StringSize_DefaultFontName()
|
||
|
|
||
|
; Check parameters are correct type
|
||
|
If Not IsString($sText) Then Return SetError(1, 1, 0)
|
||
|
If Not IsNumber($iSize) Then Return SetError(1, 2, 0)
|
||
|
If Not IsInt($iWeight) Then Return SetError(1, 3, 0)
|
||
|
If Not IsInt($iAttrib) Then Return SetError(1, 4, 0)
|
||
|
If Not IsString($sName) Then Return SetError(1, 5, 0)
|
||
|
If Not IsNumber($iMaxWidth) Then Return SetError(1, 6, 0)
|
||
|
If Not IsHwnd($hWnd) And $hWnd <> 0 Then Return SetError(1, 7, 0)
|
||
|
|
||
|
Local $aRet, $hDC, $hFont, $hLabel = 0, $hLabel_Handle
|
||
|
|
||
|
; Check for tab expansion flag
|
||
|
Local $iExpTab = BitAnd($iAttrib, 1)
|
||
|
; Remove possible tab expansion flag from font attribute value
|
||
|
$iAttrib = BitAnd($iAttrib, BitNot(1))
|
||
|
|
||
|
; If GUI handle was passed
|
||
|
If IsHWnd($hWnd) Then
|
||
|
; Create label outside GUI borders
|
||
|
$hLabel = GUICtrlCreateLabel("", -10, -10, 10, 10)
|
||
|
$hLabel_Handle = GUICtrlGetHandle(-1)
|
||
|
GUICtrlSetFont(-1, $iSize, $iWeight, $iAttrib, $sName)
|
||
|
; Create DC
|
||
|
$aRet = DllCall("user32.dll", "handle", "GetDC", "hwnd", $hLabel_Handle)
|
||
|
If @error Or $aRet[0] = 0 Then
|
||
|
GUICtrlDelete($hLabel)
|
||
|
Return SetError(2, 1, 0)
|
||
|
EndIf
|
||
|
$hDC = $aRet[0]
|
||
|
$aRet = DllCall("user32.dll", "lparam", "SendMessage", "hwnd", $hLabel_Handle, "int", 0x0031, "wparam", 0, "lparam", 0) ; $WM_GetFont
|
||
|
If @error Or $aRet[0] = 0 Then
|
||
|
GUICtrlDelete($hLabel)
|
||
|
Return SetError(2, _StringSize_Error_Close(2, $hDC), 0)
|
||
|
EndIf
|
||
|
$hFont = $aRet[0]
|
||
|
Else
|
||
|
; Get default DC
|
||
|
$aRet = DllCall("user32.dll", "handle", "GetDC", "hwnd", $hWnd)
|
||
|
If @error Or $aRet[0] = 0 Then Return SetError(2, 1, 0)
|
||
|
$hDC = $aRet[0]
|
||
|
; Create required font
|
||
|
$aRet = DllCall("gdi32.dll", "int", "GetDeviceCaps", "handle", $hDC, "int", 90) ; $LOGPIXELSY
|
||
|
If @error Or $aRet[0] = 0 Then Return SetError(2, _StringSize_Error_Close(3, $hDC), 0)
|
||
|
Local $iInfo = $aRet[0]
|
||
|
$aRet = DllCall("gdi32.dll", "handle", "CreateFontW", "int", -$iInfo * $iSize / 72, "int", 0, "int", 0, "int", 0, _
|
||
|
"int", $iWeight, "dword", BitAND($iAttrib, 2), "dword", BitAND($iAttrib, 4), "dword", BitAND($iAttrib, 8), "dword", 0, "dword", 0, _
|
||
|
"dword", 0, "dword", 5, "dword", 0, "wstr", $sName)
|
||
|
If @error Or $aRet[0] = 0 Then Return SetError(2, _StringSize_Error_Close(4, $hDC), 0)
|
||
|
$hFont = $aRet[0]
|
||
|
EndIf
|
||
|
|
||
|
; Select font and store previous font
|
||
|
$aRet = DllCall("gdi32.dll", "handle", "SelectObject", "handle", $hDC, "handle", $hFont)
|
||
|
If @error Or $aRet[0] = 0 Then Return SetError(2, _StringSize_Error_Close(5, $hDC, $hFont, $hLabel), 0)
|
||
|
Local $hPrevFont = $aRet[0]
|
||
|
|
||
|
; Declare variables
|
||
|
Local $avSize_Info[4], $iLine_Length, $iLine_Height = 0, $iLine_Count = 0, $iLine_Width = 0, $iWrap_Count, $iLast_Word, $sTest_Line
|
||
|
; Declare and fill Size structure
|
||
|
Local $tSize = DllStructCreate("int X;int Y")
|
||
|
DllStructSetData($tSize, "X", 0)
|
||
|
DllStructSetData($tSize, "Y", 0)
|
||
|
|
||
|
; Ensure EoL is @CRLF and break text into lines
|
||
|
$sText = StringRegExpReplace($sText, "((?<!\x0d)\x0a|\x0d(?!\x0a))", @CRLF)
|
||
|
Local $asLines = StringSplit($sText, @CRLF, 1)
|
||
|
|
||
|
; For each line
|
||
|
For $i = 1 To $asLines[0]
|
||
|
; Expand tabs if required
|
||
|
If $iExpTab Then
|
||
|
$asLines[$i] = StringReplace($asLines[$i], @TAB, " XXXXXXXX")
|
||
|
EndIf
|
||
|
; Size line
|
||
|
$iLine_Length = StringLen($asLines[$i])
|
||
|
DllCall("gdi32.dll", "bool", "GetTextExtentPoint32W", "handle", $hDC, "wstr", $asLines[$i], "int", $iLine_Length, "ptr", DllStructGetPtr($tSize))
|
||
|
If @error Then Return SetError(2, _StringSize_Error_Close(6, $hDC, $hFont, $hLabel), 0)
|
||
|
If DllStructGetData($tSize, "X") > $iLine_Width Then $iLine_Width = DllStructGetData($tSize, "X")
|
||
|
If DllStructGetData($tSize, "Y") > $iLine_Height Then $iLine_Height = DllStructGetData($tSize, "Y")
|
||
|
Next
|
||
|
|
||
|
; Check if $iMaxWidth has been both set and exceeded
|
||
|
If $iMaxWidth <> 0 And $iLine_Width > $iMaxWidth Then ; Wrapping required
|
||
|
; For each Line
|
||
|
For $j = 1 To $asLines[0]
|
||
|
; Size line unwrapped
|
||
|
$iLine_Length = StringLen($asLines[$j])
|
||
|
DllCall("gdi32.dll", "bool", "GetTextExtentPoint32W", "handle", $hDC, "wstr", $asLines[$j], "int", $iLine_Length, "ptr", DllStructGetPtr($tSize))
|
||
|
If @error Then Return SetError(2, _StringSize_Error_Close(6, $hDC, $hFont, $hLabel), 0)
|
||
|
; Check wrap status
|
||
|
If DllStructGetData($tSize, "X") < $iMaxWidth - 4 Then
|
||
|
; No wrap needed so count line and store
|
||
|
$iLine_Count += 1
|
||
|
$avSize_Info[0] &= $asLines[$j] & @CRLF
|
||
|
Else
|
||
|
; Wrap needed so zero counter for wrapped lines
|
||
|
$iWrap_Count = 0
|
||
|
; Build line to max width
|
||
|
While 1
|
||
|
; Zero line width
|
||
|
$iLine_Width = 0
|
||
|
; Initialise pointer for end of word
|
||
|
$iLast_Word = 0
|
||
|
; Add characters until EOL or maximum width reached
|
||
|
For $i = 1 To StringLen($asLines[$j])
|
||
|
; Is this just past a word ending?
|
||
|
If StringMid($asLines[$j], $i, 1) = " " Then $iLast_Word = $i - 1
|
||
|
; Increase line by one character
|
||
|
$sTest_Line = StringMid($asLines[$j], 1, $i)
|
||
|
; Get line length
|
||
|
$iLine_Length = StringLen($sTest_Line)
|
||
|
DllCall("gdi32.dll", "bool", "GetTextExtentPoint32W", "handle", $hDC, "wstr", $sTest_Line, "int", $iLine_Length, "ptr", DllStructGetPtr($tSize))
|
||
|
If @error Then Return SetError(2, _StringSize_Error_Close(6, $hDC, $hFont, $hLabel), 0)
|
||
|
$iLine_Width = DllStructGetData($tSize, "X")
|
||
|
; If too long exit the loop
|
||
|
If $iLine_Width >= $iMaxWidth - 4 Then ExitLoop
|
||
|
Next
|
||
|
; End of the line of text?
|
||
|
If $i > StringLen($asLines[$j]) Then
|
||
|
; Yes, so add final line to count
|
||
|
$iWrap_Count += 1
|
||
|
; Store line
|
||
|
$avSize_Info[0] &= $sTest_Line & @CRLF
|
||
|
ExitLoop
|
||
|
Else
|
||
|
; No, but add line just completed to count
|
||
|
$iWrap_Count += 1
|
||
|
; Check at least 1 word completed or return error
|
||
|
If $iLast_Word = 0 Then Return SetError(3, _StringSize_Error_Close(0, $hDC, $hFont, $hLabel), 0)
|
||
|
; Store line up to end of last word
|
||
|
$avSize_Info[0] &= StringLeft($sTest_Line, $iLast_Word) & @CRLF
|
||
|
; Strip string to point reached
|
||
|
$asLines[$j] = StringTrimLeft($asLines[$j], $iLast_Word)
|
||
|
; Trim leading whitespace
|
||
|
$asLines[$j] = StringStripWS($asLines[$j], 1)
|
||
|
; Repeat with remaining characters in line
|
||
|
EndIf
|
||
|
WEnd
|
||
|
; Add the number of wrapped lines to the count
|
||
|
$iLine_Count += $iWrap_Count
|
||
|
EndIf
|
||
|
Next
|
||
|
; Reset any tab expansions
|
||
|
If $iExpTab Then
|
||
|
$avSize_Info[0] = StringRegExpReplace($avSize_Info[0], "\x20?XXXXXXXX", @TAB)
|
||
|
EndIf
|
||
|
; Complete return array
|
||
|
$avSize_Info[1] = $iLine_Height
|
||
|
$avSize_Info[2] = $iMaxWidth
|
||
|
; Convert lines to pixels and add drop margin
|
||
|
$avSize_Info[3] = ($iLine_Count * $iLine_Height) + 4
|
||
|
Else ; No wrapping required
|
||
|
; Create return array (add drop margin to height)
|
||
|
Local $avSize_Info[4] = [$sText, $iLine_Height, $iLine_Width, ($asLines[0] * $iLine_Height) + 4]
|
||
|
EndIf
|
||
|
|
||
|
; Clear up
|
||
|
DllCall("gdi32.dll", "handle", "SelectObject", "handle", $hDC, "handle", $hPrevFont)
|
||
|
DllCall("gdi32.dll", "bool", "DeleteObject", "handle", $hFont)
|
||
|
DllCall("user32.dll", "int", "ReleaseDC", "hwnd", 0, "handle", $hDC)
|
||
|
If $hLabel Then GUICtrlDelete($hLabel)
|
||
|
|
||
|
Return $avSize_Info
|
||
|
|
||
|
EndFunc ;==>_StringSize
|
||
|
|
||
|
; #INTERNAL_USE_ONLY#============================================================================================================
|
||
|
; Name...........: _StringSize_Error_Close
|
||
|
; Description ...: Releases DC and deleted font object if required after error
|
||
|
; Syntax ........: _StringSize_Error_Close ($iExtCode, $hDC, $hGUI)
|
||
|
; Parameters ....: $iExtCode - code to return
|
||
|
; $hDC, $hGUI - handles as set in _StringSize function
|
||
|
; Return value ..: $iExtCode as passed
|
||
|
; Author ........: Melba23
|
||
|
; Modified.......:
|
||
|
; Remarks .......: This function is used internally by _StringSize
|
||
|
; ===============================================================================================================================
|
||
|
Func _StringSize_Error_Close($iExtCode, $hDC = 0, $hFont = 0, $hLabel = 0)
|
||
|
|
||
|
If $hFont <> 0 Then DllCall("gdi32.dll", "bool", "DeleteObject", "handle", $hFont)
|
||
|
If $hDC <> 0 Then DllCall("user32.dll", "int", "ReleaseDC", "hwnd", 0, "handle", $hDC)
|
||
|
If $hLabel Then GUICtrlDelete($hLabel)
|
||
|
|
||
|
Return $iExtCode
|
||
|
|
||
|
EndFunc ;=>_StringSize_Error_Close
|
||
|
|
||
|
; #INTERNAL_USE_ONLY#============================================================================================================
|
||
|
; Name...........: _StringSize_DefaultFontName
|
||
|
; Description ...: Determines Windows default font
|
||
|
; Syntax ........: _StringSize_DefaultFontName()
|
||
|
; Parameters ....: None
|
||
|
; Return values .: Success - Returns name of system default font
|
||
|
; Failure - Returns "Tahoma"
|
||
|
; Author ........: Melba23, based on some original code by Larrydalooza
|
||
|
; Modified.......:
|
||
|
; Remarks .......: This function is used internally by _StringSize
|
||
|
; ===============================================================================================================================
|
||
|
Func _StringSize_DefaultFontName()
|
||
|
|
||
|
; Get default system font data
|
||
|
Local $tNONCLIENTMETRICS = DllStructCreate("uint;int;int;int;int;int;byte[60];int;int;byte[60];int;int;byte[60];byte[60];byte[60]")
|
||
|
DLLStructSetData($tNONCLIENTMETRICS, 1, DllStructGetSize($tNONCLIENTMETRICS))
|
||
|
DLLCall("user32.dll", "int", "SystemParametersInfo", "int", 41, "int", DllStructGetSize($tNONCLIENTMETRICS), "ptr", DllStructGetPtr($tNONCLIENTMETRICS), "int", 0)
|
||
|
Local $tLOGFONT = DllStructCreate("long;long;long;long;long;byte;byte;byte;byte;byte;byte;byte;byte;char[32]", DLLStructGetPtr($tNONCLIENTMETRICS, 13))
|
||
|
If IsString(DllStructGetData($tLOGFONT, 14)) Then
|
||
|
Return DllStructGetData($tLOGFONT, 14)
|
||
|
Else
|
||
|
Return "Tahoma"
|
||
|
EndIf
|
||
|
|
||
|
EndFunc ;=>_StringSize_DefaultFontName
|