Jump to content

Recommended Posts

Posted (edited)

Per-Monitor v2 DPI Awareness Scaling Test:

Have this GUI running and test by changing your DPI scaling settings from: Settings app > System > Display > Scale

Work in progress, but might become more interesting. Possible UDF if everything goes well.

EDIT: My initial script forgot to set the initial DPI scaled values. 🤦‍♂️

#include <GuiEdit.au3>
#include <FontConstants.au3>
#include <WindowsNotifsConstants.au3>
#include <WinAPISysWin.au3>
#include <WinAPIGdi.au3>
#include <GUIConstantsEx.au3>
#include <AutoItConstants.au3>
#include <StructureConstants.au3>

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

Global $g_iScale = _WinAPI_GetDPIForWindow(WinGetHandle(AutoItWinGetTitle())) / 96
If @error Then $g_iScale = 1
Global $g_hCtrlFont = 0

Global Const $fDefFontSize = 8.5, $fDefPixel = $fDefFontSize * 96 / 72 

Global Const $WM_DPICHANGED = 0x02E0
Global Const $WM_GETDPISCALEDSIZE = 0x02E4
Global Const $WM_DPICHANGED_BEFOREPARENT = 0x02E2
Global Const $WM_DPICHANGED_AFTERPARENT = 0x02E3

OnAutoItExitRegister("_Cleanup")

Example()

Func Example()
    Local $iCtrlSpaceV = 15
    Local $sAppName = "Testing PerMonitorV2 DPI"
    Local $hGUI = GUICreate($sAppName, 440, 340, -1, -1)

    Local $idTestName = GUICtrlCreateLabel("Test Name:", 15, 20, -1, -1)
    Local $aPos = ControlGetPos($hGUI, "", $idTestName)
    Local $iPrev = $aPos[1] + $aPos[3] + $iCtrlSpaceV

    Local $idTestInput = GUICtrlCreateInput("Test Input", 15, $iPrev, 300, 22 * $g_iScale)
    Local $aPos = ControlGetPos($hGUI, "", $idTestInput)
    Local $iPrev = $aPos[1] + $aPos[3] + $iCtrlSpaceV

    Local $idCheckbox1 = GUICtrlCreateCheckbox("Test Checkbox1 ", 15, $iPrev)
    Local $aPos = ControlGetPos($hGUI, "", $idCheckbox1)
    Local $iPrev = $aPos[1] + $aPos[3] + $iCtrlSpaceV

    Local $idCheckbox2 = GUICtrlCreateCheckbox("Test Checkbox2 ", 15, $iPrev)
    Local $aPos = ControlGetPos($hGUI, "", $idCheckbox2)
    Local $iPrev = $aPos[1] + $aPos[3] + $iCtrlSpaceV

    _GUICtrlEdit_Create($hGUI, "This is a test" & @CRLF & "Another Line", 15, $iPrev, 394, 64 * $g_iScale)

    GUISetState(@SW_SHOW, $hGUI)

    GUIRegisterMsg($WM_DPICHANGED, _WM_DPICHANGED)

    While 1
        Switch GUIGetMsg()
            Case $GUI_EVENT_CLOSE
                ExitLoop

        EndSwitch
    WEnd

    GUIDelete($hGUI)
EndFunc   ;==>Example

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

    Local Static $iInitDPI = $g_iScale
    Local Static $iPrevDPI = $g_iScale

    ; Obtain new DPI values
    Local $iDPI = _WinAPI_LoWord($wParam)
    Local $iNewDPI = _WinAPI_LoWord($wParam) / 96

    Local $hFont = $g_hCtrlFont

    ; Create new scaled font
    $g_hCtrlFont = _WinAPI_CreateFont(-Round($fDefPixel * $iNewDPI), 0, 0, 0, $FW_NORMAL, False, False, False, _
            $DEFAULT_CHARSET, $OUT_DEFAULT_PRECIS, $CLIP_DEFAULT_PRECIS, $PROOF_QUALITY, $DEFAULT_PITCH, "Segoe UI")

    ; Lock window drawing for smoother transition
    _WinAPI_LockWindowUpdate($hWnd)

    ; Enumerate child windows for sizing adjustments
    Local $aCtrls = _WinAPI_EnumChildWindows($hWnd, False)
    Local $hCtrl, $sClass, $aPos, $tPoint, $iX, $iY, $iW, $iH, $iOrigDPI
    If IsArray($aCtrls) Then
        For $i = 1 To $aCtrls[0][0]
            $hCtrl = $aCtrls[$i][0]
            $sClass = $aCtrls[$i][1]
            $aPos = WinGetPos($hCtrl)
            $tPoint = DllStructCreate("int X;int Y")
            DllStructSetData($tPoint, "X", $aPos[0])
            DllStructSetData($tPoint, "Y", $aPos[1])

            ; Convert screen coordinates to client
            _WinAPI_ScreenToClient($hWnd, $tPoint)
            $iX = DllStructGetData($tPoint, "X")
            $iY = DllStructGetData($tPoint, "Y")
            $iW = _WinAPI_GetWindowWidth($hCtrl)
            $iH = _WinAPI_GetWindowHeight($hCtrl)

            ; Divide value by previous DPI factor to get original size, then multiply by new DPI factor (rounded to nearest .5)
            $iX = Round((($iX / $iPrevDPI) * $iNewDPI) / 0.5) * 0.5
            $iY = Round((($iY / $iPrevDPI) * $iNewDPI) / 0.5) * 0.5
            $iW = Round((($iW / $iPrevDPI) * $iNewDPI) / 0.5) * 0.5
            $iH = Round((($iH / $iPrevDPI) * $iNewDPI) / 0.5) * 0.5

            ; Set new position/sizes for control
            Local $iCtrlID = _WinAPI_GetDlgCtrlID($hCtrl)
            If $iCtrlID < 10000 Then
                GUICtrlSetResizing($iCtrlID, $GUI_DOCKLEFT + $GUI_DOCKTOP + $GUI_DOCKWIDTH + $GUI_DOCKHEIGHT)
                GUICtrlSetPos($iCtrlID, $iX, $iY, $iW, $iH) ; working for GUICtrlCreate* controls only
            ElseIf $iCtrlID >= 10000 Then
                ControlMove($hWnd, "", $iCtrlID, $iX, $iY, $iW, $iH) ; working for UDF-created controls only
            ElseIf Not $iCtrlID Then
                ; probably custom SysLink or something which has no CtrlID
                ; can't move without CtrlID
                ; only need to modify X here
            EndIf

            ; Set new scaled font to each control
            _SendMessage($hCtrl, $WM_SETFONT, $g_hCtrlFont, True)
        Next
    EndIf

    ; Resize GUI window
    Local $tRECT = DllStructCreate($tagRECT, $lParam)
    Local $iX = $tRECT.left, $iY = $tRECT.top, $iW = $tRECT.right - $iX, $iH = $tRECT.bottom - $iY
    _WinAPI_SetWindowPos($hWnd, 0, $iX, $iY, $iW, $iH, BitOR($SWP_NOZORDER, $SWP_NOACTIVATE))

    ;
    ; IMPORTANT: Desperately need a GUICtrlGetResizing() function to restore original control resizing behavior
    ;

    ; Update previous DPI with the now current DPI
    $iPrevDPI = $iNewDPI

    _WinAPI_LockWindowUpdate(0)

    ; Delete previous font
    If $hFont Then _WinAPI_DeleteObject($hFont)

    Return 0
EndFunc   ;==>_WM_DPICHANGED

Func _Cleanup()
    _WinAPI_DeleteObject($g_hCtrlFont)
EndFunc

Func _WinAPI_GetDPIForWindow($hWnd) ; UEZ
    Local $aResult = DllCall('user32.dll', "uint", "GetDpiForWindow", "hwnd", $hWnd) ;requires Win10 v1607+ / no server support
    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

 

Edited by WildByDesign
Posted

It is rather cumbersome to have to wrap and then compute each control individually. At the very least, I have not been able to think of a better approach—for instance, one that would allow the interface to become fully adaptive simply by adding a function or a parameter.

#include <GuiEdit.au3>
#include <FontConstants.au3>
#include <WindowsNotifsConstants.au3>
#include <WinAPISysWin.au3>
#include <WinAPIGdi.au3>
#include <GUIConstantsEx.au3>
#include <AutoItConstants.au3>
#include <StructureConstants.au3>

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

Global $g_iScale = 1
Global $g_hCtrlFont = 0

Global Const $fDefFontSize = 8.5, $fDefPixel = $fDefFontSize * 96 / 72

Global Const $WM_DPICHANGED = 0x02E0
Global Const $WM_GETDPISCALEDSIZE = 0x02E4
Global Const $WM_DPICHANGED_BEFOREPARENT = 0x02E2
Global Const $WM_DPICHANGED_AFTERPARENT = 0x02E3

Global $g_aCtrlDesign[1][5] = [[0]]
Global $g_iDesignClientW = 440, $g_iDesignClientH = 340
Global $g_iFrameW = 0, $g_iFrameH = 0

OnAutoItExitRegister("_Cleanup")

Example()

Func Example()
    Local $sAppName = "Testing PerMonitorV2 DPI"
    Local $hGUI = GUICreate($sAppName, $g_iDesignClientW, $g_iDesignClientH)

    _DPICtrlCreateLabel("Test Name:", 15, 20)
    _DPICtrlCreateInput("Test Input", 15, 50, 300, 24)
    _DPICtrlCreateCheckbox("Test Checkbox1 ", 15, 85)
    _DPICtrlCreateCheckbox("Test Checkbox2 ", 15, 110)
    _DPICtrlEditCreate($hGUI, "This is a test" & @CRLF & "Another Line", 15, 140, 394, 80)

    $g_iScale = _WinAPI_GetDPIForWindow($hGUI) / 96
    If @error Then $g_iScale = 1

    Local $aWin = WinGetPos($hGUI)
    Local $aClient = WinGetClientSize($hGUI)
    $g_iFrameW = $aWin[2] - $aClient[0]
    $g_iFrameH = $aWin[3] - $aClient[1]

    _ApplyDPI($hGUI, $g_iScale * 96)

    GUISetState(@SW_SHOW, $hGUI)

    GUIRegisterMsg($WM_DPICHANGED, _WM_DPICHANGED)

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

    GUIDelete($hGUI)
EndFunc   ;==>Example

; ------------------------------------------------------------------------------
; Wrapper functions – auto‑register each control with its design size
; ------------------------------------------------------------------------------

Func _DPICtrlCreateLabel($sText, $iX, $iY, $iW = -1, $iH = -1, $iStyle = -1, $iExStyle = -1)
    Local $id = GUICtrlCreateLabel($sText, $iX, $iY, $iW, $iH, $iStyle, $iExStyle)
    Local $hCtrl = GUICtrlGetHandle($id)
    Local $iRealW = $iW, $iRealH = $iH
    If $iW = -1 Or $iH = -1 Then
        Local $aRect = _WinAPI_GetWindowRect($hCtrl)
        If Not @error And IsArray($aRect) Then
            If $iW = -1 Then $iRealW = $aRect[2] - $aRect[0]
            If $iH = -1 Then $iRealH = $aRect[3] - $aRect[1]
        Else
            If $iW = -1 Then $iRealW = 100
            If $iH = -1 Then $iRealH = 20
        EndIf
    EndIf
    _AddDesignCtrl($hCtrl, $iX, $iY, $iRealW, $iRealH)
    Return $id
EndFunc

Func _DPICtrlCreateInput($sText, $iX, $iY, $iW, $iH, $iStyle = -1, $iExStyle = -1)
    Local $id = GUICtrlCreateInput($sText, $iX, $iY, $iW, $iH, $iStyle, $iExStyle)
    _AddDesignCtrl(GUICtrlGetHandle($id), $iX, $iY, $iW, $iH)
    Return $id
EndFunc

Func _DPICtrlCreateCheckbox($sText, $iX, $iY, $iW = -1, $iH = -1, $iStyle = -1)
    Local $id = GUICtrlCreateCheckbox($sText, $iX, $iY, $iW, $iH, $iStyle)
    Local $hCtrl = GUICtrlGetHandle($id)
    Local $iRealW = $iW, $iRealH = $iH
    If $iW = -1 Or $iH = -1 Then
        Local $aRect = _WinAPI_GetWindowRect($hCtrl)
        If Not @error And IsArray($aRect) Then
            If $iW = -1 Then $iRealW = $aRect[2] - $aRect[0]
            If $iH = -1 Then $iRealH = $aRect[3] - $aRect[1]
        Else
            If $iW = -1 Then $iRealW = 120
            If $iH = -1 Then $iRealH = 20
        EndIf
    EndIf
    _AddDesignCtrl($hCtrl, $iX, $iY, $iRealW, $iRealH)
    Return $id
EndFunc

Func _DPICtrlEditCreate($hGUI, $sText, $iX, $iY, $iW, $iH, $iStyle = -1, $iExStyle = -1)
    Local $hEdit = _GUICtrlEdit_Create($hGUI, $sText, $iX, $iY, $iW, $iH, $iStyle, $iExStyle)
    _AddDesignCtrl($hEdit, $iX, $iY, $iW, $iH)
    Return $hEdit
EndFunc

; Store control’s design dimensions (96 DPI)
Func _AddDesignCtrl($hCtrlOrID, $iX, $iY, $iW, $iH)
    Local $hCtrl = GUICtrlGetHandle($hCtrlOrID)
    If $hCtrl = 0 Then $hCtrl = $hCtrlOrID
    Local $iCount = UBound($g_aCtrlDesign, 1)
    ReDim $g_aCtrlDesign[$iCount + 1][5]
    $g_aCtrlDesign[$iCount][0] = $hCtrl
    $g_aCtrlDesign[$iCount][1] = $iX
    $g_aCtrlDesign[$iCount][2] = $iY
    $g_aCtrlDesign[$iCount][3] = $iW
    $g_aCtrlDesign[$iCount][4] = $iH
    $g_aCtrlDesign[0][0] = $iCount
EndFunc

; ------------------------------------------------------------------------------
; DPI change handler – keeps your original variable naming and logic flow
; ------------------------------------------------------------------------------

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

    Local Static $iInitDPI = $g_iScale
    Local Static $iPrevDPI = $g_iScale

    ; Obtain new DPI value (raw)
    Local $iDPI = _WinAPI_LoWord($wParam)
    Local $iNewDPI = $iDPI / 96

    _ApplyDPI($hWnd, $iDPI, DllStructCreate($tagRECT, $lParam))

    Return 0
EndFunc   ;==>_WM_DPICHANGED

; ------------------------------------------------------------------------------
; Core scaling function
; ------------------------------------------------------------------------------

Func _ApplyDPI($hWnd, $iDPI, $tRect = 0)
    Local $iNewDPI = $iDPI / 96
    If $iNewDPI == $g_iScale And $g_hCtrlFont Then Return

    Local $hFont = $g_hCtrlFont
    $g_hCtrlFont = _WinAPI_CreateFont(-Round($fDefPixel * $iNewDPI), 0, 0, 0, $FW_NORMAL, False, False, False, _
            $DEFAULT_CHARSET, $OUT_DEFAULT_PRECIS, $CLIP_DEFAULT_PRECIS, $PROOF_QUALITY, $DEFAULT_PITCH, "Segoe UI")

    _WinAPI_LockWindowUpdate($hWnd)

    ; Adjust window size
    If IsDllStruct($tRect) Then
        ; Use suggested rectangle from the system
        Local $iX = DllStructGetData($tRect, "Left")
        Local $iY = DllStructGetData($tRect, "Top")
        Local $iW = DllStructGetData($tRect, "Right") - $iX
        Local $iH = DllStructGetData($tRect, "Bottom") - $iY
        _WinAPI_SetWindowPos($hWnd, 0, $iX, $iY, $iW, $iH, $SWP_NOZORDER)

        ; Recalculate frame difference after system resize
        Local $aNewWin = WinGetPos($hWnd)
        Local $aNewClient = WinGetClientSize($hWnd)
        $g_iFrameW = $aNewWin[2] - $aNewClient[0]
        $g_iFrameH = $aNewWin[3] - $aNewClient[1]
    Else
        ; First‑time scaling: compute new client area and center the window
        Local $iNewClientW = Round($g_iDesignClientW * $iNewDPI)
        Local $iNewClientH = Round($g_iDesignClientH * $iNewDPI)
        Local $iNewWinW = $iNewClientW + $g_iFrameW
        Local $iNewWinH = $iNewClientH + $g_iFrameH
        WinMove($hWnd, "", Default, Default, $iNewWinW, $iNewWinH)
        _CenterWindow($hWnd)
    EndIf

    ; Enumerate child controls from the design array and apply new positions/sizes
    Local $aCtrls = $g_aCtrlDesign
    For $i = 1 To $aCtrls[0][0]
        Local $hCtrl = $aCtrls[$i][0]
        Local $sClass = "" ; not used but kept for compatibility with original structure
        If Not IsHWnd($hCtrl) Then ContinueLoop

        ; Calculate new coordinates and dimensions directly from design sizes
        Local $iX = Round($aCtrls[$i][1] * $iNewDPI)
        Local $iY = Round($aCtrls[$i][2] * $iNewDPI)
        Local $iW = Round($aCtrls[$i][3] * $iNewDPI)
        Local $iH = Round($aCtrls[$i][4] * $iNewDPI)

        ; Move control using its handle
        _WinAPI_SetWindowPos($hCtrl, 0, $iX, $iY, $iW, $iH, $SWP_NOZORDER)

        ; Set the new scaled font
        _SendMessage($hCtrl, $WM_SETFONT, $g_hCtrlFont, True)
    Next

    ; Update previous DPI factor
    $g_iScale = $iNewDPI

    _WinAPI_LockWindowUpdate(0)

    ; Delete previous font
    If $hFont Then _WinAPI_DeleteObject($hFont)
EndFunc   ;==>_ApplyDPI


Func _CenterWindow($hWnd)
    Local $aWin = WinGetPos($hWnd)
    If Not IsArray($aWin) Then Return
    Local $iW = $aWin[2], $iH = $aWin[3]
    Local $aWork = _GetWorkArea()
    Local $iX = ($aWork[2] - $aWork[0] - $iW) / 2 + $aWork[0]
    Local $iY = ($aWork[3] - $aWork[1] - $iH) / 2 + $aWork[1]
    WinMove($hWnd, "", $iX, $iY)
EndFunc

Func _GetWorkArea()
    Local $tRect = DllStructCreate($tagRECT)
    DllCall("user32.dll", "bool", "SystemParametersInfoW", "uint", 0x0030, "uint", 0, "struct*", $tRect, "uint", 0)
    Local $aRect[4] = [DllStructGetData($tRect, "Left"), DllStructGetData($tRect, "Top"), _
                        DllStructGetData($tRect, "Right"), DllStructGetData($tRect, "Bottom")]
    Return $aRect
EndFunc

Func _Cleanup()
    _WinAPI_DeleteObject($g_hCtrlFont)
EndFunc

Func _WinAPI_GetDPIForWindow($hWnd) ; UEZ
    Local $aResult = DllCall('user32.dll', "uint", "GetDpiForWindow", "hwnd", $hWnd) ;requires Win10 v1607+ / no server support
    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

 

Posted (edited)
24 minutes ago, fanxing said:

It is rather cumbersome to have to wrap and then compute each control individually. At the very least, I have not been able to think of a better approach—for instance, one that would allow the interface to become fully adaptive simply by adding a function or a parameter.

This is fantastic. Your modified example worked wonderfully. Excellent work! :)

I updated my initial example now because when I posted it last night, I had completely forgotten to scale the initial control sizes by the DPI factor which is why it got off to a bad start especially on 200% or higher.

EDIT: By the way, the more that I read your updated code example, the more brilliant that I realize it is. I've got a lot to learn and your updated example will absolutely help me learn more. So I am very thankful.

Edited by WildByDesign
  • 3 weeks later...
Posted (edited)

For Per-Monitor v2 DPI awareness (needed in PMv2 UDF and GUIDarkTheme UDF), I needed a way to accurately obtain the LOGFONT and create font handle with the exact menubar font that is being used on a system level. And on top of that, I needed the scaled LOGFONT especially so that I could update the menubar font anytime WM_DPICHANGED is handled. WM_DPICHANGED gets the new DPI value and, at least in my usage, would then send that DPI as a parameter to the following new function:

Func _GetSystemMenuFont($iDPI = 96)
    Local $tNCM = DllStructCreate("uint cbSize;int iBorderWidth;int iScrollWidth;int iScrollHeight;" & _
            "int iCaptionWidth;int iCaptionHeight;byte lfCaptionFont[92];" & _
            "int iSmCaptionWidth;int iSmCaptionHeight;byte lfSmCaptionFont[92];" & _
            "int iMenuWidth;int iMenuHeight;byte lfMenuFont[92];" & _
            "byte lfStatusFont[92];byte lfMessageFont[92];int iPaddedBorderWidth")

    DllStructSetData($tNCM, "cbSize", DllStructGetSize($tNCM))

    Local $aResult = DllCall("user32.dll", "bool", "SystemParametersInfoForDpi", _
            "uint", $SPI_GETNONCLIENTMETRICS, _
            "uint", DllStructGetSize($tNCM), _
            "ptr", DllStructGetPtr($tNCM), _
            "uint", 0, _
            "uint", $iDPI)

    ; Obtain LOGFONT structure for system menu font
    Local $tLogFont = DllStructCreate("long lfHeight;long lfWidth;long lfEscapement;long lfOrientation;" & _
            "long lfWeight;byte lfItalic;byte lfUnderline;byte lfStrikeOut;byte lfCharSet;" & _
            "byte lfOutPrecision;byte lfClipPrecision;byte lfQuality;byte lfPitchAndFamily;" & _
            "wchar lfFaceName[32]", DllStructGetPtr($tNCM, "lfMenuFont"))

    ; Obtain font handle for system menu font
    Local $hMenuFont = _WinAPI_CreateFontIndirect($tLogFont)

    Return $hMenuFont
EndFunc   ;==>_GetSystemMenuFont

It works perfectly. And as usual, you still need to manage deleting font resources and such. So I create an updated font on DPI change and delete the previous font.

Edited by WildByDesign
Posted (edited)

Add font icons (Segoe Fluent Icons, Segoe MDL2 Assets, etc.) directly to ImageLists.

You can specify font name, unicode hex, size and color and add to any ImageList for use in ListViews, TreeViews, Toolbars, tab controls and much more.

This is a similar concept to my previous _CreateToolbarIconFromFont() function. However, this adds color and also adds directly to ImageList.

Oh... and it is significantly sharper and smoother overall. 🤩

#include <GUIConstantsEx.au3>
#include <GuiImageList.au3>
#include <GuiListView.au3>
#include <GDIPlus.au3>
#include <WinAPITHeme.au3>

DllCall("User32.dll", "bool", "SetProcessDpiAwarenessContext", "int_ptr", -2)

Local $hGUI = GUICreate("Add Font Icons To ImageList", 600, 400)
GUISetBkColor(0x000000)

Local $iSize = 64
Local $hImageList = _GUIImageList_Create($iSize, $iSize, 5, 3) 

; Add icons to the ImageList
_AddFontIconToImageList($hImageList, "Segoe Fluent Icons", 0xE713, $iSize, 0xFF0078D4) ; Settings
_AddFontIconToImageList($hImageList, "Segoe Fluent Icons", 0xE80F, $iSize, 0xFF107C10) ; Home
_AddFontIconToImageList($hImageList, "Segoe Fluent Icons", 0xE74E, $iSize, 0xFFD83B01) ; Save

Local $idListView = GUICtrlCreateListView("Icon Name        |Description", 20, 20, 560, 360, BitOR($GUI_SS_DEFAULT_LISTVIEW, $LVS_NOCOLUMNHEADER))
GUICtrlSetBkColor(-1, 0x202020)
GUICtrlSetColor(-1, 0xFFFFFF)

_GUICtrlListView_SetImageList($idListView, $hImageList, 1) ; 1 = Small icon list

Local $idItem1 = GUICtrlCreateListViewItem("Settings|Modify application settings", $idListView)
Local $idItem2 = GUICtrlCreateListViewItem("Home|Return to main menu", $idListView)
Local $idItem3 = GUICtrlCreateListViewItem("Save|Save current project changes", $idListView)

_GUICtrlListView_SetItemImage(GUICtrlGetHandle($idListView), 0, 0)
_GUICtrlListView_SetItemImage(GUICtrlGetHandle($idListView), 1, 1)
_GUICtrlListView_SetItemImage(GUICtrlGetHandle($idListView), 2, 2)


GUISetState(@SW_SHOW)

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

; Clean up resources
_GUIImageList_Destroy($hImageList)
GUIDelete($hGUI)

Func _AddFontIconToImageList($hImageList, $sFontName, $iUnicodeDecimalOrHex, $iSize = 32, $iARGBColor = 0xFF000000)
    _GDIPlus_Startup()

    ; Render at 2x resolution for supersampling sharpness
    Local $iRenderSize = $iSize * 2 

    Local $hBitmap  = _GDIPlus_BitmapCreateFromScan0($iRenderSize, $iRenderSize)
    Local $hGraphics     = _GDIPlus_ImageGetGraphicsContext($hBitmap)
    
    ; Use high quality rendering and ClearType hint
    _GDIPlus_GraphicsSetSmoothingMode($hGraphics, 2)
    _GDIPlus_GraphicsSetInterpolationMode($hGraphics, $GDIP_INTERPOLATIONMODE_HIGHQUALITYBICUBIC)
    _GDIPlus_GraphicsSetTextRenderingHint($hGraphics, $GDIP_TEXTRENDERINGHINTCLEARTYPEGRIDFIT)

    Local $hBrush  = _GDIPlus_BrushCreateSolid($iARGBColor)
    Local $hFamily = _GDIPlus_FontFamilyCreate($sFontName)
    Local $hFont   = _GDIPlus_FontCreate($hFamily, $iRenderSize * 0.48, 0, 3)
    Local $tLayout = _GDIPlus_RectFCreate(0, 0, $iRenderSize, $iRenderSize)

    Local $hFormat = _GDIPlus_StringFormatCreate()
    _GDIPlus_StringFormatSetAlign($hFormat, 1)
    _GDIPlus_StringFormatSetLineAlign($hFormat, 1)

    Local $sChar = ChrW($iUnicodeDecimalOrHex)
    _GDIPlus_GraphicsDrawStringEx($hGraphics, $sChar, $hFont, $tLayout, $hFormat, $hBrush)

    ; Create final target size bitmap and downscale smoothly
    Local $hFinalBitmap = _GDIPlus_BitmapCreateFromScan0($iSize, $iSize)
    Local $hFinalGraphics    = _GDIPlus_ImageGetGraphicsContext($hFinalBitmap)
    _GDIPlus_GraphicsSetInterpolationMode($hFinalGraphics, $GDIP_INTERPOLATIONMODE_HIGHQUALITYBICUBIC)
    _GDIPlus_GraphicsDrawImageRect($hFinalGraphics, $hBitmap, 0, 0, $iSize, $iSize)

    ; Convert to HBITMAP
    Local $hHBITMAP = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hFinalBitmap)
    _GUIImageList_Add($hImageList, $hHBITMAP, 0)

    ; Clean up all handles
    _WinAPI_DeleteObject($hHBITMAP)
    _GDIPlus_StringFormatDispose($hFormat)
    _GDIPlus_FontDispose($hFont)
    _GDIPlus_FontFamilyDispose($hFamily)
    _GDIPlus_BrushDispose($hBrush)
    _GDIPlus_GraphicsDispose($hFinalGraphics)
    _GDIPlus_BitmapDispose($hFinalBitmap)
    _GDIPlus_GraphicsDispose($hGraphics)
    _GDIPlus_BitmapDispose($hBitmap)
    _GDIPlus_Shutdown()
    
    Return 1
EndFunc   ;==>_AddFontIconToImageList

 

Edited by WildByDesign

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...