ioa747 Posted July 31 Author Posted July 31 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. argumentum and pixelsearch 2 I know that I know nothing
pixelsearch Posted July 31 Posted July 31 @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 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 ioa747 1 "I think you are searching a bug where there is no bug... don't listen to bad advice."
ioa747 Posted July 31 Author Posted July 31 @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. argumentum, pixelsearch and WildByDesign 3 I know that I know nothing
ioa747 Posted August 1 Author Posted August 1 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 )) Thank you once again for the continuous feedback and support! I updated the first post with the new version. pixelsearch 1 I know that I know nothing
ioa747 Posted August 4 Author Posted August 4 (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 expandcollapse popup; 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 August 4 by ioa747 WildByDesign 1 I know that I know nothing
WildByDesign Posted August 4 Posted August 4 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. ioa747 1
Dan_555 Posted August 6 Posted August 6 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. ioa747 1 Some of my script sourcecode
ioa747 Posted August 7 Author Posted August 7 @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
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now