Jump to content

Recommended Posts

Posted

In this update,
I refactored the keyboard navigation logic to make it cleaner and completely naturally.

What changed

Removed HotKeySet for TAB navigation
Now handles native control focus cycling naturally without any key hooking.

Replace with _WinAPI_GetFocus() 
A function inside the main loop compares the current focus window handle against the previous state.

Clean Visual States
It automatically detects when focus moves into or out of the fake combos (via TAB, Shift+TAB, or mouse clicks) and updates the active highlight state.
 

Thank you once again   :)
for the continuous feedback and support!
 

I updated the first post  with the new version.

I know that I know nothing

Posted

@ioa747 Hello :)
Glad you got rid of the HotKeySet for TAB navigation.
I got a question : is the script below the way to retrieve what is returned from Font_Dialog.au3 in light mode ?

#include <AutoItConstants.au3>
#include <GUIConstantsEx.au3>
#include <MsgBoxConstants.au3>

Example()

Func Example()
    Local $hGUI = GUICreate("Test Font_Dialog 0.21", 400, 250)
    Local $idTest = GUICtrlCreateButton("Choose Font", 20, 20, 100, 30)
    Local $iPID, $sRead

    GUISetState(@SW_SHOW, $hGUI)

    While 1
        Switch GUIGetMsg()
            Case $GUI_EVENT_CLOSE
                ExitLoop

            Case $idTest
                GUICtrlSetState($idTest, $GUI_DISABLE)
                $iPID = Run(@AutoItExe & " " & chr(34) & @ScriptDir & "\Font_Dialog.au3" & chr(34), _
                    @ScriptDir, @SW_HIDE, $STDOUT_CHILD)
                ProcessWaitClose($iPID)
                $sRead = StdoutRead($iPID)
                MsgBox($MB_TOPMOST, "Returned from Font_Dialog", $sRead, 0, $hGUI)
                GUICtrlSetState($idTest, $GUI_ENABLE)
        EndSwitch
    WEnd

    GuiDelete($hGUI)
EndFunc   ;==>Example

 

TestFont_Dialog1.png.d719fa1f0d859ddc3f0d20ea5e79638f.png

After that, I made another test and tried a single ConsoleWrite in Font_Dialog.au3

ConsoleWrite($aResult) ; without splitting it in Font_Dialog.au3

Then this is what could be used in the calling script, it may be more user friendly... or not :D

TestFont_Dialog2.png.f863a3b825e47dbf0a1a5d353116b050.png

"I think you are searching a bug where there is no bug... don't listen to bad advice."

Posted

@pixelsearch  Following the path you have shown me  (The use of  StdoutRead)


Refactored Font_Dialog.au3 to use  _CmdLine_Parsing() to pass Parameters to _Custom_Font_Gui() 
Supported flags: /Name: /Size: /Color: /Weight: /Attribute: /Parent: /DarkMode:

changed Function Signature
_Custom_Font_Gui($sFontName = "Segoe UI", $iPointSize = 10, $iFontColorRef = Default, $iFontWeight = 400, $iAttribute = 0, $hWndParent = 0, $iDarkMode = 0)

 

In the Example

Refactored _Font_Dlg() 
to use Option Strings / Named Parameters

Instead of using a traditional long parameter list with fixed positional arguments
(where you had to pass Default for unused parameters just to reach $hWndParent or $iDarkMode),

_Font_Dlg() now accepts a single Option String.

What changed:
Cleaner Function Signature

Old: _Font_Dlg($sName, $iSize, $iColor, $iWeight, $iAttribute, $hWndParent, $iDarkMode)

New: _Font_Dlg([$sOptions = ""])

Pass-Through CLI Architecture
The wrapper parses the options string and forwards only the specified parameters directly to Font_Dialog.au3.
Omitted parameters automatically fall back to their internal default values inside Font_Dialog.au3.

Safe String Encoding
The /Name: parameter is automatically isolated and encoded to Binary/Hex (StringToBinary($sNameVal, 4))
before passing to CLI to safely handle font family names containing spaces or special characters.

Why this approach is better
You no longer need to write _Font_Dlg(Default, Default, Default, Default, Default, $hGUI, 1)
Now simply pass _Font_Dlg("/Parent:" & $hGUI & " /DarkMode:1")

Order-independent
Switches can be provided in any order (/Size:12 /Name:Segoe UI or /Name:Segoe UI /Size:12)

Keep It Simple Principle
Keeps the wrapper function ultra-lightweight (~20 lines) without redundant variable parsing or re-building logic.

(However, I also left the original version for comparison.)

Thank you once again   :)
for the continuous feedback and support!
 

I updated the first post  with the new version.

 

I know that I know nothing

Posted

I made some minor corrections

e.g. if the Parsing color is in the list, pass it by name in the combobox

Result allway as hex string, with $sResult &= "0x" & Hex(GUICtrlRead($g_idColorSample), 6)

I put an icon in the GUI

I changed the default values in _Custom_Font_Gui() to
$iFontColorRef = 0 (which is black)
$iFontWeight = 0 (which is Dontcare (as a typical Autoit User :D))

 

Thank you once again   :)
for the continuous feedback and support!
 

I updated the first post  with the new version.

I know that I know nothing

Posted (edited)

@WildByDesign  Because Font_Dialog.au3 was a school for me in PER_MONITOR_AWARE_V2 DPI Awareness

by adapting your example to the logic of Font_Dialog.au3 you can have an automated adaptation system even with different fonts

adapted example

; https://www.autoitscript.com/forum/topic/213805-custom-font-dialog-box/page/2/#findComment-1554049
#AutoIt3Wrapper_Au3Check_Parameters=-d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6 -w 7
#include <GuiEdit.au3>
#include <FontConstants.au3>
#include <WindowsNotifsConstants.au3>
#include <WinAPISysWin.au3>
#include <WinAPIGdi.au3>
#include <GUIConstantsEx.au3>
#include <AutoItConstants.au3>
#include <StructureConstants.au3>
#include <Debug.au3>

; Enable PER_MONITOR_AWARE_V2 DPI Awareness
DllCall("User32.dll", "bool", "SetProcessDpiAwarenessContext", "int_ptr", -4)

; Register cleanup function to release GDI resources on script exit
OnAutoItExitRegister("_Cleanup")

Global $g_fDpiScale = 1.0
Global Const $WM_DPICHANGED = 0x02E0

Example()

Func Example()
    Local $iCtrlSpaceV = 15
    Local $sAppName = "Testing PerMonitorV2 DPI (Hybrid Strategy)"
    Local $hGUI = GUICreate($sAppName, 440, 340, -1, -1)
    ; GUISetFont(11, $FW_NORMAL, $GUI_FONTNORMAL, "Segoe UI")

    Local $idTestName = GUICtrlCreateLabel("Test Name:", 15, 20, 100, 25)
    GUICtrlSetFont(-1, 14, 600, $GUI_FONTNORMAL, "Segoe UI")
    Local $aPos = ControlGetPos($hGUI, "", $idTestName)
    Local $iPrev = $aPos[1] + $aPos[3] + $iCtrlSpaceV

    Local $idTestInput = GUICtrlCreateInput("Test Input", 15, $iPrev, 300, 24)
    GUICtrlSetFont(-1, 12, $FW_NORMAL, $GUI_FONTNORMAL, "Segoe UI")
    $aPos = ControlGetPos($hGUI, "", $idTestInput)
    $iPrev = $aPos[1] + $aPos[3] + $iCtrlSpaceV

    Local $idCheckbox1 = GUICtrlCreateCheckbox("Test Checkbox1 ", 15, $iPrev, 180, 20)
    GUICtrlSetFont(-1, 8, $FW_NORMAL, $GUI_FONTNORMAL, "Segoe UI")
    $aPos = ControlGetPos($hGUI, "", $idCheckbox1)
    $iPrev = $aPos[1] + $aPos[3] + $iCtrlSpaceV

    Local $idCheckbox2 = GUICtrlCreateCheckbox("Test Checkbox2 ", 15, $iPrev, 180, 20)
    GUICtrlSetFont(-1, 8, $FW_NORMAL, $GUI_FONTNORMAL, "Segoe UI")
    $aPos = ControlGetPos($hGUI, "", $idCheckbox2)
    $iPrev = $aPos[1] + $aPos[3] + $iCtrlSpaceV

    ; Create UDF control (returns HWND handle directly)
    Local $hEdit = _GUICtrlEdit_Create($hGUI, "This is a test" & @CRLF & "Another Line", 15, $iPrev, 394, 80)

    ; Create GDI Font for 11pt Segoe UI (-15px height at 100% DPI)
    Local $iInitHeight = -Round((11 / 72) * (_WinAPI_GetDPIForWindow($hGUI)))
    Local $hInitFont = _WinAPI_CreateFont($iInitHeight, 0, 0, 0, $FW_NORMAL, False, False, False, _
            $DEFAULT_CHARSET, $OUT_DEFAULT_PRECIS, $CLIP_DEFAULT_PRECIS, $PROOF_QUALITY, $DEFAULT_PITCH, "Segoe UI")

    ; Apply font to UDF control via $WM_SETFONT (0x0030)
    _SendMessage($hEdit, 0x0030, $hInitFont, True)

    ; Initialize DPI scaling for GUI and child controls BEFORE showing the window
    _AdJustDpi($hGUI, True)

    _WinAPI_DeleteObject($hInitFont)

    GUIRegisterMsg($WM_DPICHANGED, _WM_DPICHANGED)
    GUISetState(@SW_SHOW, $hGUI)

    While 1
        Switch GUIGetMsg()
            Case $GUI_EVENT_CLOSE
                ExitLoop
        EndSwitch
    WEnd

    GUIDelete($hGUI)
EndFunc   ;==>Example

Func _WM_DPICHANGED($hWnd, $iMsg, $wParam, $lParam)
    #forceref $iMsg, $lParam

    ; Resize main GUI window according to suggested RECT from Windows ($lParam)
    Local $tRECT = DllStructCreate($tagRECT, $lParam)
    Local $iNewX = DllStructGetData($tRECT, "left")
    Local $iNewY = DllStructGetData($tRECT, "top")
    Local $iNewW = DllStructGetData($tRECT, "right") - $iNewX
    Local $iNewH = DllStructGetData($tRECT, "bottom") - $iNewY

    _WinAPI_SetWindowPos($hWnd, 0, $iNewX, $iNewY, $iNewW, $iNewH, BitOR($SWP_NOZORDER, $SWP_NOACTIVATE))

    ; Retrieve target DPI scale factor from LOWORD wParam
    $g_fDpiScale = _WinAPI_LoWord($wParam) / 96

    ; Adjust controls layout
    _AdJustDpi($hWnd, False)

    Return 0
EndFunc   ;==>_WM_DPICHANGED

Func _AdJustDpi($hWnd, $bInit = False)
    ; Columns: [0: HWND, 1: BaseX, 2: BaseY, 3: BaseW, 4: BaseH, 5: BaseFontPt, 6: Weight, 7: Attribute, 8: FaceName, 9: hCreatedFont]
    Local Static $aBaseCtrls[1][10]
    Local Static $fPrimaryMonitorDpiScale = 0

    ; === SCRIPT EXIT GDI CLEANUP ===
    If $hWnd == 0 Then
        If $aBaseCtrls[0][0] > 0 Then
            For $i = 1 To $aBaseCtrls[0][0]
                If $aBaseCtrls[$i][9] Then
                    _WinAPI_DeleteObject($aBaseCtrls[$i][9])
                    $aBaseCtrls[$i][9] = 0
                EndIf
            Next
        EndIf
        Return
    EndIf

    Local $hCtrl, $fBasePt, $iWeight, $iAttribute, $sFontname

    If $bInit Then
        ; Capture Primary Monitor DPI Scale factor during initialization
        $fPrimaryMonitorDpiScale = _WinAPI_GetDPIForWindow($hWnd) / 96
        If @error Or $fPrimaryMonitorDpiScale = 0 Then $fPrimaryMonitorDpiScale = 1.0
        $g_fDpiScale = $fPrimaryMonitorDpiScale

        ; Enumerate all child controls belonging to the parent window
        Local $aCtrls = _WinAPI_EnumChildWindows($hWnd, False)
        If IsArray($aCtrls) Then
            ReDim $aBaseCtrls[$aCtrls[0][0] + 1][10]
            $aBaseCtrls[0][0] = $aCtrls[0][0]

            Local $tPoint = DllStructCreate("int X;int Y")
            Local $tLOGFONT = DllStructCreate($tagLOGFONT)
            Local $aPos, $hFont, $iPixelHeight

            For $i = 1 To $aCtrls[0][0]
                $hCtrl = $aCtrls[$i][0]
                $aPos = WinGetPos($hCtrl)

                DllStructSetData($tPoint, "X", $aPos[0])
                DllStructSetData($tPoint, "Y", $aPos[1])
                _WinAPI_ScreenToClient($hWnd, $tPoint)

                ; Default fallback values per control iteration
                $fBasePt = 8.5
                $iWeight = $FW_NORMAL
                $iAttribute = 0
                $sFontname = "Segoe UI"

                ; Retrieve control LOGFONT structure via $WM_GETFONT (0x0031)
                $hFont = _SendMessage($hCtrl, 0x0031, 0, 0)

                If $hFont Then
                    If _WinAPI_GetObject($hFont, DllStructGetSize($tLOGFONT), DllStructGetPtr($tLOGFONT)) Then
                        $iPixelHeight = Abs(DllStructGetData($tLOGFONT, "Height"))

                        If $iPixelHeight > 0 Then
                            $fBasePt = ($iPixelHeight * 72 / 96) / $g_fDpiScale
                            ; $fBasePt = Round($fBasePt * 2) / 2
                            $fBasePt = Round($fBasePt)
                            ;ConsoleWrite("$fBasePt=" & $fBasePt & @CRLF)

                            $iWeight = DllStructGetData($tLOGFONT, "Weight")
                            $sFontname = DllStructGetData($tLOGFONT, "FaceName")

                            $iAttribute = 0
                            If DllStructGetData($tLOGFONT, "Italic") Then $iAttribute = BitOR($iAttribute, 2)
                            If DllStructGetData($tLOGFONT, "Underline") Then $iAttribute = BitOR($iAttribute, 4)
                            If DllStructGetData($tLOGFONT, "StrikeOut") Then $iAttribute = BitOR($iAttribute, 8)
                        EndIf
                    EndIf
                EndIf

                ; Store Base 100% Coordinates, Full Font Metadata and GDI Handle slot
                $aBaseCtrls[$i][0] = $hCtrl
                $aBaseCtrls[$i][1] = DllStructGetData($tPoint, "X")
                $aBaseCtrls[$i][2] = DllStructGetData($tPoint, "Y")
                $aBaseCtrls[$i][3] = _WinAPI_GetWindowWidth($hCtrl)
                $aBaseCtrls[$i][4] = _WinAPI_GetWindowHeight($hCtrl)
                $aBaseCtrls[$i][5] = $fBasePt
                $aBaseCtrls[$i][6] = $iWeight
                $aBaseCtrls[$i][7] = $iAttribute
                $aBaseCtrls[$i][8] = $sFontname
                $aBaseCtrls[$i][9] = 0 ; Initialize custom GDI Font Handle
            Next
        EndIf

        ; Adjust main window size if initial monitor DPI is not 100%
        If $g_fDpiScale <> 1.0 Then
            Local $aWinPos = WinGetPos($hWnd)
            _WinAPI_SetWindowPos($hWnd, 0, $aWinPos[0], $aWinPos[1], Round($aWinPos[2] * $g_fDpiScale), Round($aWinPos[3] * $g_fDpiScale), BitOR($SWP_NOZORDER, $SWP_NOACTIVATE))
        EndIf

;~      _DebugArrayDisplay($aBaseCtrls) ; _DebugArrayDisplay <<<
    EndIf

    ; Calculate relative DPI ratio for Native Controls font scaling
    Local $iDpiCurrent = Round($g_fDpiScale * 96)
    Local $iDpiPrimary = Round($fPrimaryMonitorDpiScale * 96)
    Local $fDpiRatio = $iDpiCurrent / $iDpiPrimary

    _WinAPI_LockWindowUpdate($hWnd)

    Local $fScaledPt, $iX, $iY, $iW, $iH, $iCtrlID
    Local $iUdfPixelHeight, $hNewUdfFont, $hPrevUdfFont

    For $i = 1 To $aBaseCtrls[0][0]
        $hCtrl = $aBaseCtrls[$i][0]

        ; Scaled Position & Size based on 100% Base coordinates
        $iX = Round($aBaseCtrls[$i][1] * $g_fDpiScale)
        $iY = Round($aBaseCtrls[$i][2] * $g_fDpiScale)
        $iW = Round($aBaseCtrls[$i][3] * $g_fDpiScale)
        $iH = Round($aBaseCtrls[$i][4] * $g_fDpiScale)

        $fBasePt = $aBaseCtrls[$i][5]
        $iWeight = $aBaseCtrls[$i][6]
        $iAttribute = $aBaseCtrls[$i][7]
        $sFontname = $aBaseCtrls[$i][8]

        $iCtrlID = _WinAPI_GetDlgCtrlID($hCtrl)
        If $iCtrlID > 0 And $iCtrlID < 10000 Then
            ; === NATIVE AUTOIT CONTROL ===
            GUICtrlSetPos($iCtrlID, $iX, $iY, $iW, $iH)

            $fScaledPt = $fBasePt * $fDpiRatio
            GUICtrlSetFont($iCtrlID, $fScaledPt, $iWeight, $iAttribute, $sFontname, $CLEARTYPE_QUALITY)
        Else
            ; === UDF / HWND CONTROL ===
            _WinAPI_MoveWindow($hCtrl, $iX, $iY, $iW, $iH, True)

            ; Calculate cell pixel height for Win32 API CreateFont
            $iUdfPixelHeight = -Round(($fBasePt * 96 / 72) * $g_fDpiScale)

            ; Store previously allocated custom GDI handle for safe cleanup
            $hPrevUdfFont = $aBaseCtrls[$i][9]

            ; Create new DPI-scaled GDI Font
            $hNewUdfFont = _WinAPI_CreateFont($iUdfPixelHeight, 0, 0, 0, $iWeight, _
                    BitAND($iAttribute, 2) <> 0, BitAND($iAttribute, 4) <> 0, BitAND($iAttribute, 8) <> 0, _
                    $DEFAULT_CHARSET, $OUT_DEFAULT_PRECIS, $CLIP_DEFAULT_PRECIS, $PROOF_QUALITY, $DEFAULT_PITCH, $sFontname)

            ; Update control font via $WM_SETFONT (0x0030)
            _SendMessage($hCtrl, 0x0030, $hNewUdfFont, True)

            ; Store new GDI handle and delete the previously created custom handle
            $aBaseCtrls[$i][9] = $hNewUdfFont
            If $hPrevUdfFont Then _WinAPI_DeleteObject($hPrevUdfFont)
        EndIf
    Next
    _WinAPI_LockWindowUpdate(0)
EndFunc   ;==>_AdJustDpi

Func _WinAPI_GetDPIForWindow($hWnd)
    Local $aResult = DllCall("user32.dll", "uint", "GetDpiForWindow", "hwnd", $hWnd)
    If Not IsArray($aResult) Or @error Then Return SetError(1, @extended, 0)
    If Not $aResult[0] Then Return SetError(2, @extended, 0)
    Return $aResult[0]
EndFunc   ;==>_WinAPI_GetDPIForWindow

Func _Cleanup()
    _AdJustDpi(0)
EndFunc   ;==>_Cleanup

 

Please, every comment is appreciated!
leave your comments and experiences here!
Thank you very much  :)

 

Edited by ioa747

I know that I know nothing

Posted
5 hours ago, ioa747 said:

by adapting your example to the logic of Font_Dialog.au3 you can have an automated adaptation system even with different fonts

adapted example

This is incredible work. Visually it looks sharp and perfect on all scaling settings. But the logic and techniques that you use in your code is also special to me because I see a bunch of techniques in there for me to learn from. Thank you for sharing. :)

Posted

One thing on my "Wish list" would be to be able to change the text from the "Font sample display on the fly". 
Maybe to have 2 buttons which would change the text, one for the standard "fox jumps over ... "

and the other for the troublesome characters, which may look similar like  iIlL1 oO0qQ and other ... 
Sometime the similarities are not obvious in a string, but appear when written near each other.

To be able to compare these in a Font Dialog would be, imho, great.

Some of my script sourcecode

Posted

@Dan_555 

following your idea
However, instead of buttons, I put a new parameter in the signature

; #FUNCTION# ====================================================================================================================
; Name ..........: _Font_Dlg
; Description ...: Calls the external Font_Dialog process to select font properties.
; Syntax ........: _Font_Dlg([$sOptions = ""])
; Parameters ....: $sOptions - [optional] CLI parameter string.
;                  Supported flags: /Name: /Size: /Color: /Weight: /Attribute: /Parent: /DarkMode: /Sample:
; Return values .: Success - Returns 1D Array: [1]=Size, [2]=Weight, [3]=Attribute, [4]=FontName, [5]=Color
;                  Failure - Sets @error = 1 and returns ""
; Example .......: _Font_Dlg("/Parent:" & $hGUI & " /Name:Segoe UI /Size:12")
; ===============================================================================================================================

allowing the user to call the function with a custom sample
(something like this)
 

Local $sSample = "Sample which may look similar like  iIlL1 oO0qQ and other ... "
Local $aFont = _Font_Dlg("/Parent:" & $hGUI & " /Name:'Segoe Script' /Size:10 /DarkMode:0 /Color:" & 0xFF6A00 & " /Sample:'" & $sSample & "'")

 

Please, every comment is appreciated!
leave your comments and experiences here!
Thank you very much  :)

I know that I know nothing

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...