Jump to content

Resizable status bar without SBARS_SIZEGRIP


Go to solution Solved by pixelsearch,

Recommended Posts

Posted

For what it's worth, here is what ended up working for me:

;==============================================
Func WM_MOVE($hWnd, $iMsg, $wParam, $lParam)
    #forceref $iMsg, $wParam, $lParam
    Local Static $bSizeboxOffScreen = False

    If $hWnd = $g_hGUI Then
        Local $aPos = WinGetPos($g_hSizebox)
        If $aPos[0] + $aPos[2] > @DesktopWidth Or $aPos[1] + $aPos[3] > @DesktopHeight Then
            $bSizeboxOffScreen = True
        Else
            If $bSizeboxOffScreen Then
                ; sizebox was off-screen but is back in range now, redraw GUI
                _WinAPI_RedrawWindow($g_hGui)
                $bSizeboxOffScreen = False
            EndIf
        EndIf
        _WinAPI_RedrawWindow($g_hSizebox)
    EndIf
    Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_MOVE

Keep in mind that this may or may not work in a multi-monitor setup. However, multi-monitor setups require quite a bit different DPI scaling settings and so on. So this is quite basic but it works 100% of the time for me. :)

Posted

I just wanted to share an updated version of the CreateDots function which matches the Windows gripper dots identically. The dot size, dot spacing and placement on the statusbar is a perfect match now at 100%, 125%, 150% and 175% DPI scaling. Please note, my monitor does not do 200% scaling or higher and therefore 200% and higher are untested.

The dots are so accurate that I tested by removing the ownerdrawn parts and applied light mode Explorer theme to the statusbar which shows the default gripper dots. I then used System Informer to hide/unhide the "Scrollbar" window and everything was perfect at 100%, 125%, 150% and 175% DPI scaling. I am a little bit frustrated that I can't test anything higher.

Changes:

; set base DPI scale value and apply DPI
Global $iDPI = 1
ApplyDPI()
; DPI needs to be applied before the Example() function
Func ApplyDPI()
    ; apply System DPI awareness
    DllCall("User32.dll", "bool", "SetProcessDpiAwarenessContext" , "HWND", "DPI_AWARENESS_CONTEXT" -2)
    ; update DPI scale value based on DPI scaling already applied to AutoIt hidden window
    $iDPI = Round(_WinAPI_GetDpiForWindow(WinGetHandle(AutoItWinGetTitle())) / 96, 2)
    If @error Then $iDPI = 1
EndFunc

...

;==============================================
Func CreateDots($iWidth, $iHeight, $iBackgroundColor, $iDotsColor) ; Andreik
    Local $iDotSize, $iDotSpace, $iDotFrame
    Switch $iDPI
        Case 1      ; 100% scaling
            $iDotSize = 2
            $iDotSpace = $iDotSize - 1  ; ensures that dots have only 1 pixel of space between
            $iDotFrame = -1             ; controls the distance from frame
            Local $a[6][2] = [[3,9], [3,6], [3,3], [6,6], [6,3], [9,3]]
        Case 1.25   ; 125% scaling
            $iDotSize = 3
            $iDotSpace = $iDotSize - 1
            $iDotFrame = 1
            Local $a[6][2] = [[3,7], [3,5], [3,3], [5,5], [5,3], [7,3]]
        Case 1.5    ; 150% scaling
            $iDotSize = 3
            $iDotSpace = $iDotSize - 1
            $iDotFrame = 1
            Local $a[6][2] = [[3,7], [3,5], [3,3], [5,5], [5,3], [7,3]]
        Case 1.75   ; 175% scaling
            $iDotSize = 3
            $iDotSpace = $iDotSize - 1
            $iDotFrame = 1
            Local $a[6][2] = [[3,7], [3,5], [3,3], [5,5], [5,3], [7,3]]
        Case 2      ; 200% scaling
            $iDotSize = 4
            $iDotSpace = $iDotSize - 1
            $iDotFrame = 1
            Local $a[6][2] = [[3,7], [3,5], [3,3], [5,5], [5,3], [7,3]]
        Case Else
            $iDotSize = 1
            $iDotSpace = $iDotSize - 1
            $iDotFrame = 1
            Local $a[6][2] = [[3,7], [3,5], [3,3], [5,5], [5,3], [7,3]]
    EndSwitch
    Local $hBitmap = _GDIPlus_BitmapCreateFromScan0($iWidth, $iHeight)
    Local $hGraphics = _GDIPlus_ImageGetGraphicsContext($hBitmap)
    Local $hBrush = _GDIPlus_BrushCreateSolid($iDotsColor)
    _GDIPlus_GraphicsClear($hGraphics, $iBackgroundColor)
    For $i = 0 To UBound($a) - 1
        _GDIPlus_GraphicsFillRect($hGraphics, $iWidth - ($iDotSpace * $a[$i][0]) + $iDotFrame, $iHeight - ($iDotSpace * $a[$i][1]) + $iDotFrame, $iDotSize, $iDotSize, $hBrush)
    Next
    _GDIPlus_BrushDispose($hBrush)
    _GDIPlus_GraphicsDispose($hGraphics)
    Return $hBitmap
EndFunc   ;==>CreateDots

...

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

 

And here is the full working script:

#include <GDIPlus.au3>
#include <GUIConstantsEx.au3>
#include <GuiStatusBar.au3>
#include <StaticConstants.au3>
#include <WinAPIGdi.au3>
#include <WinAPIRes.au3>
#include <WinAPISysWin.au3>
#include <WinAPITheme.au3>
#include <WindowsConstants.au3>

Opt("MustDeclareVars", 1)

Global $g_hGui, $g_hSizebox, $g_hOldProc, $g_hStatus, $g_iHeight, $g_aText, $g_aRatioW, $g_iBkColor, $g_iTextColor, $g_hDots
; Global $g_hBrush ; no need, as _GUICtrlStatusBar_SetBkColor() placed after _WinAPI_SetWindowTheme() does the job correctly

; set base DPI scale value and apply DPI
Global $iDPI = 1
ApplyDPI()

Func ApplyDPI()
    ; apply System DPI awareness
    DllCall("User32.dll", "bool", "SetProcessDpiAwarenessContext" , "HWND", "DPI_AWARENESS_CONTEXT" -2)
    ; update DPI scale value based on DPI scaling already applied to AutoIt hidden window
    $iDPI = Round(_WinAPI_GetDpiForWindow(WinGetHandle(AutoItWinGetTitle())) / 96, 2)
    If @error Then $iDPI = 1
EndFunc

Example()

;==============================================
Func Example()

    _GDIPlus_Startup()

    Local Const $SBS_SIZEBOX = 0x08, $SBS_SIZEGRIP = 0x10
    Local $iW = 300, $iH = 100
    Dim $g_iBkColor = 0x383838, $g_iTextColor = 0xFFFFFF

    $g_hGui = GUICreate("Resize corner", $iW, $iH, -1, -1, $WS_OVERLAPPEDWINDOW)
    GUISetBkColor($g_iBkColor)

    ;-----------------
    ; Create a sizebox window (Scrollbar class) BEFORE creating the StatusBar control
    $g_hSizebox = _WinAPI_CreateWindowEx(0, "Scrollbar", "", $WS_CHILD + $WS_VISIBLE + $SBS_SIZEBOX, _
        0, 0, 0, 0, $g_hGui) ; $SBS_SIZEBOX or $SBS_SIZEGRIP

    ; Subclass the sizebox (by changing the window procedure associated with the Scrollbar class)
    Local $hProc = DllCallbackRegister('ScrollbarProc', 'lresult', 'hwnd;uint;wparam;lparam')
    $g_hOldProc = _WinAPI_SetWindowLong($g_hSizebox, $GWL_WNDPROC, DllCallbackGetPtr($hProc))

    Local $hCursor = _WinAPI_LoadCursor(0, $OCR_SIZENWSE)
    _WinAPI_SetClassLongEx($g_hSizebox, -12, $hCursor) ; $GCL_HCURSOR = -12

    ; $g_hBrush = _WinAPI_CreateSolidBrush($g_iBkColor)

    ;-----------------
    $g_hStatus = _GUICtrlStatusBar_Create($g_hGui, -1, "", $WS_CLIPSIBLINGS) ; ClipSiblings style +++
    Local $aParts[3] = [90, 180, 280]
    If $aParts[Ubound($aParts) - 1] = -1 Then $aParts[Ubound($aParts) - 1] = $iW ; client width size
    _MyGUICtrlStatusBar_SetParts($g_hStatus, $aParts)

    Dim $g_aText[Ubound($aParts)] = ["Part 0", "Part 1", "Part 2"]
    Dim $g_aRatioW[Ubound($aParts)]
    For $i = 0 To UBound($g_aText) - 1
        _GUICtrlStatusBar_SetText($g_hStatus, "", $i, $SBT_OWNERDRAW)
        ; _GUICtrlStatusBar_SetText($g_hStatus, "", $i, $SBT_OWNERDRAW + $SBT_NOBORDERS) ; interesting ?
        $g_aRatioW[$i] = $aParts[$i] / $iW
    Next

    Local $idChangeText = GUICtrlCreateLabel("Change Text", 110, 25, 80, 30, $SS_CENTER + $SS_CENTERIMAGE), $iInc
    GUICtrlSetColor(-1, 0xFFFF00) ; yellow

    ; to allow the setting of StatusBar BkColor at least under Windows 10
    _WinAPI_SetWindowTheme($g_hStatus, "", "")

    ; Set status bar background color
    _GUICtrlStatusBar_SetBkColor($g_hStatus, $g_iBkColor)

    $g_iHeight = _GUICtrlStatusBar_GetHeight($g_hStatus) + 3 ; change the constant (+3) if necessary
    $g_hDots = CreateDots($g_iHeight, $g_iHeight, 0xFF000000 + $g_iBkColor, 0xFF000000 + $g_iTextColor)

    GUIRegisterMsg($WM_SIZE, "WM_SIZE")
    GUIRegisterMsg($WM_MOVE, "WM_MOVE")
    GUIRegisterMsg($WM_DRAWITEM, "WM_DRAWITEM")
    GUISetState()

    While 1
        Switch GUIGetMsg()
            Case $GUI_EVENT_CLOSE
                ExitLoop

            Case $idChangeText
                $iInc += 1
                For $i = 0 To UBound($g_aText) - 1
                    $g_aText[$i] = "Part " & $i & " : Inc " & $iInc
                Next
                _WinAPI_RedrawWindow($g_hStatus)
        EndSwitch
    WEnd

    _GDIPlus_BitmapDispose($g_hDots)
    _GUICtrlStatusBar_Destroy($g_hStatus)
    _WinAPI_DestroyCursor($hCursor)
    ; _WinAPI_DeleteObject($g_hBrush)
    _WinAPI_SetWindowLong($g_hSizebox, $GWL_WNDPROC, $g_hOldProc)
    DllCallbackFree($hProc)
    _GDIPlus_Shutdown()
EndFunc   ;==>Example

;==============================================
Func ScrollbarProc($hWnd, $iMsg, $wParam, $lParam) ; Andreik

    If $iMsg = $WM_PAINT Then
        Local $tPAINTSTRUCT
        Local $hDC = _WinAPI_BeginPaint($hWnd, $tPAINTSTRUCT)
        Local $iWidth = DllStructGetData($tPAINTSTRUCT, 'rPaint', 3) - DllStructGetData($tPAINTSTRUCT, 'rPaint', 1)
        Local $iHeight = DllStructGetData($tPAINTSTRUCT, 'rPaint', 4) - DllStructGetData($tPAINTSTRUCT, 'rPaint', 2)
        Local $hGraphics = _GDIPlus_GraphicsCreateFromHDC($hDC)
        _GDIPlus_GraphicsDrawImageRect($hGraphics, $g_hDots, 0, 0, $iWidth, $iHeight)
        _GDIPlus_GraphicsDispose($hGraphics)
        _WinAPI_EndPaint($hWnd, $tPAINTSTRUCT)
        Return 0
    EndIf
    Return _WinAPI_CallWindowProc($g_hOldProc, $hWnd, $iMsg, $wParam, $lParam)
EndFunc   ;==>ScrollbarProc

;==============================================
Func CreateDots($iWidth, $iHeight, $iBackgroundColor, $iDotsColor) ; Andreik
    Local $iDotSize, $iDotSpace, $iDotFrame
    Switch $iDPI
        Case 1      ; 100% scaling
            $iDotSize = 2
            $iDotSpace = $iDotSize - 1  ; ensures that dots have only 1 pixel of space between
            $iDotFrame = -1             ; controls the distance from frame
            Local $a[6][2] = [[3,9], [3,6], [3,3], [6,6], [6,3], [9,3]]
        Case 1.25   ; 125% scaling
            $iDotSize = 3
            $iDotSpace = $iDotSize - 1
            $iDotFrame = 1
            Local $a[6][2] = [[3,7], [3,5], [3,3], [5,5], [5,3], [7,3]]
        Case 1.5    ; 150% scaling
            $iDotSize = 3
            $iDotSpace = $iDotSize - 1
            $iDotFrame = 1
            Local $a[6][2] = [[3,7], [3,5], [3,3], [5,5], [5,3], [7,3]]
        Case 1.75   ; 175% scaling
            $iDotSize = 3
            $iDotSpace = $iDotSize - 1
            $iDotFrame = 1
            Local $a[6][2] = [[3,7], [3,5], [3,3], [5,5], [5,3], [7,3]]
        Case 2      ; 200% scaling
            $iDotSize = 4
            $iDotSpace = $iDotSize - 1
            $iDotFrame = 1
            Local $a[6][2] = [[3,7], [3,5], [3,3], [5,5], [5,3], [7,3]]
        Case Else
            $iDotSize = 1
            $iDotSpace = $iDotSize - 1
            $iDotFrame = 1
            Local $a[6][2] = [[3,7], [3,5], [3,3], [5,5], [5,3], [7,3]]
    EndSwitch
    Local $hBitmap = _GDIPlus_BitmapCreateFromScan0($iWidth, $iHeight)
    Local $hGraphics = _GDIPlus_ImageGetGraphicsContext($hBitmap)
    Local $hBrush = _GDIPlus_BrushCreateSolid($iDotsColor)
    _GDIPlus_GraphicsClear($hGraphics, $iBackgroundColor)
    For $i = 0 To UBound($a) - 1
        _GDIPlus_GraphicsFillRect($hGraphics, $iWidth - ($iDotSpace * $a[$i][0]) + $iDotFrame, $iHeight - ($iDotSpace * $a[$i][1]) + $iDotFrame, $iDotSize, $iDotSize, $hBrush)
    Next
    _GDIPlus_BrushDispose($hBrush)
    _GDIPlus_GraphicsDispose($hGraphics)
    Return $hBitmap
EndFunc   ;==>CreateDots

;==============================================
Func CreateDots_old($iWidth, $iHeight, $iBackgroundColor, $iDotsColor) ; Andreik

    Local $iDotSize = Int($iHeight / 10)
    Local $hBitmap = _GDIPlus_BitmapCreateFromScan0($iWidth, $iHeight)
    Local $hGraphics = _GDIPlus_ImageGetGraphicsContext($hBitmap)
    Local $hBrush = _GDIPlus_BrushCreateSolid($iDotsColor)
    _GDIPlus_GraphicsClear($hGraphics, $iBackgroundColor)
    Local $a[6][2] = [[2,6], [2,4], [2,2], [4,4], [4,2], [6,2]]
    For $i = 0 To UBound($a) - 1
        _GDIPlus_GraphicsFillRect($hGraphics, $iWidth - $iDotSize * $a[$i][0], $iHeight - $iDotSize * $a[$i][1], $iDotSize, $iDotSize, $hBrush)
    Next
    _GDIPlus_BrushDispose($hBrush)
    _GDIPlus_GraphicsDispose($hGraphics)
    Return $hBitmap
EndFunc   ;==>CreateDots_old

;==============================================
Func _MyGUICtrlStatusBar_SetParts($hWnd, $aPartEdge) ; Pixelsearch

    If Not IsArray($aPartEdge) Then Return False
    Local $iParts = UBound($aPartEdge)
    Local $tParts = DllStructCreate("int[" & $iParts & "]")
    For $i = 0 To $iParts - 1
        DllStructSetData($tParts, 1, $aPartEdge[$i], $i + 1)
    Next
    DllCall("user32.dll", "lresult", "SendMessageW", "hwnd", $hWnd, "uint", $SB_SETPARTS, "wparam", $iParts, "struct*", $tParts)
    _GUICtrlStatusBar_Resize($hWnd)
    Return True
EndFunc   ;==>_MyGUICtrlStatusBar_SetParts

;==============================================
Func WM_SIZE($hWnd, $iMsg, $wParam, $lParam) ; Pixelsearch
    #forceref $iMsg, $wParam, $lParam

    If $hWnd = $g_hGUI Then
        Local Static $bIsSizeBoxShown = True
        Local $aSize = WinGetClientSize($g_hGui)
        Local $aGetParts = _GUICtrlStatusBar_GetParts($g_hStatus)
        Local $aParts[$aGetParts[0]]
        For $i = 0 To $aGetParts[0] - 1
            $aParts[$i] = Int($aSize[0] * $g_aRatioW[$i])
        Next
        If BitAND(WinGetState($g_hGui), $WIN_STATE_MAXIMIZED) Then
            _GUICtrlStatusBar_SetParts($g_hStatus, $aParts) ; set parts until GUI right border (AutoIt function forces it)
            _WinAPI_ShowWindow($g_hSizebox, @SW_HIDE)
            $bIsSizeBoxShown = False
        Else
            If $g_aRatioW[UBound($aParts) -1] <> 1 Then $aParts[UBound($aParts) -1] = $aSize[0] - $g_iHeight ; right size of right part stuck on sizebox (no gap)
            _MyGUICtrlStatusBar_SetParts($g_hStatus, $aParts) ; set parts until sizebox (see preceding line) or until GUI right border
            WinMove($g_hSizebox, "", $aSize[0] - $g_iHeight, $aSize[1] - $g_iHeight, $g_iHeight, $g_iHeight)
            If Not $bIsSizeBoxShown Then
                _WinAPI_ShowWindow($g_hSizebox, @SW_SHOW)
                $bIsSizeBoxShown = True
            EndIf
        EndIf
    EndIf
    Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_SIZE

;==============================================
Func WM_MOVE($hWnd, $iMsg, $wParam, $lParam)
    #forceref $iMsg, $wParam, $lParam

    If $hWnd = $g_hGUI Then
        _WinAPI_RedrawWindow($g_hSizebox)
    EndIf
    Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_MOVE

;==============================================
Func WM_DRAWITEM($hWnd, $iMsg, $wParam, $lParam) ; Kafu
    #forceref $hWnd, $iMsg, $wParam

    Local Static $tagDRAWITEM = "uint CtlType;uint CtlID;uint itemID;uint itemAction;uint itemState;hwnd hwndItem;handle hDC;long rcItem[4];ulong_ptr itemData"
    Local $tDRAWITEM = DllStructCreate($tagDRAWITEM, $lParam)
    If $tDRAWITEM.hwndItem <> $g_hStatus Then Return $GUI_RUNDEFMSG ; only process the statusbar

    Local $itemID = $tDRAWITEM.itemID ; status bar part number : 0 if simple bar (or 0, 1, 2... if multi parts)
    Local $hDC = $tDRAWITEM.hDC
    Local $tRect = DllStructCreate("long left;long top;long right;long bottom", DllStructGetPtr($tDRAWITEM, "rcItem"))
    ; _WinAPI_FillRect($hDC, DllStructGetPtr($tRect), $g_hBrush) ; backgound color
    _WinAPI_SetTextColor($hDC, $g_iTextColor) ; text color
    _WinAPI_SetBkMode($hDC, $TRANSPARENT)
    DllStructSetData($tRect, "top", $tRect.top + 1)
    DllStructSetData($tRect, "left", $tRect.left + 1)
    _WinAPI_DrawText($hDC, $g_aText[$itemID], $tRect, $DT_LEFT)

    Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_DRAWITEM

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)

with sacrifice ?  :)
 

#include <GUIConstantsEx.au3>
#include <GuiStatusBar.au3>
#include <StaticConstants.au3>
#include <WinAPIGdi.au3>
#include <WindowsConstants.au3>
#include <WinAPITheme.au3>


Opt("MustDeclareVars", 1)

Global $g_hGui, $g_idSizeGrip, $g_hStatus, $g_iHeight
Global $g_iBkColor = 0x383838, $g_iTextColor = 0xFFFFFF
Global $iDPI = 1
Global $g_iGripW = _WinAPI_GetSystemMetrics($SM_CXVSCROLL)

; Initialize arrays properly at start
Global $g_aText[3] = ["Part 0", "Part 1", "Part 2"]
Global $g_aRatioW[3] = [0.3, 0.6, 1.0] ; Proportions for resizing

ApplyDPI()

Example()

;---------------------------------------------------------------------------------------
Func Example() ; Create Main GUI
    Local $iW = 400, $iH = 200

    ; Create Main GUI
    $g_hGui = GUICreate("Resize Corner ", $iW, $iH, -1, -1, $WS_OVERLAPPEDWINDOW)
    GUISetBkColor($g_iBkColor)

    ; Create StatusBar
    _Create_StatusBar($iW, $iH)

    Local $idChangeText = GUICtrlCreateLabel("Change Text", 110, 25, 80, 30, $SS_CENTER + $SS_CENTERIMAGE), $iInc
    GUICtrlSetColor(-1, 0xFFFF00) ; yellow
    GUICtrlSetResizing(-1, $GUI_DOCKSIZE)

    ; Register Messages for real-time response
    GUIRegisterMsg($WM_SIZE, "WM_SIZE")
    GUIRegisterMsg($WM_DRAWITEM, "WM_DRAWITEM")

    GUISetState(@SW_SHOW)

    While 1
        Switch GUIGetMsg()
            Case $GUI_EVENT_CLOSE
                ExitLoop

            Case $idChangeText
                $iInc += 1
                For $i = 0 To UBound($g_aText) - 1
                    $g_aText[$i] = "Part " & $i & " : Inc " & $iInc
                Next
                _WinAPI_RedrawWindow($g_hGui)

        EndSwitch
    WEnd
EndFunc   ;==>Example
;---------------------------------------------------------------------------------------
Func _Create_StatusBar($iW, $iH) ; Create StatusBar

    $g_hStatus = _GUICtrlStatusBar_Create($g_hGui, -1, "", $WS_CLIPSIBLINGS)
    _WinAPI_SetWindowTheme($g_hStatus, "", "")
    _GUICtrlStatusBar_SetBkColor($g_hStatus, $g_iBkColor)

    ; Initial Parts setup
    Local $aInitialParts[3] = [Int($iW * 0.3), Int($iW * 0.6), $iW - $g_iGripW]
    _MyGUICtrlStatusBar_SetParts($g_hStatus, $aInitialParts)

    For $i = 0 To UBound($g_aText) - 1
        _GUICtrlStatusBar_SetText($g_hStatus, "", $i, $SBT_OWNERDRAW)
    Next

    ; Create the Grip Label 0x2591(░) or 0x2592(▒) or 0x2593(▓)
    $g_iHeight = _GUICtrlStatusBar_GetHeight($g_hStatus)
    $g_idSizeGrip = GUICtrlCreateLabel(ChrW(0x2591), $iW - $g_iGripW, $iH - $g_iHeight - 3, $g_iGripW, $g_iHeight + 3)

    GUICtrlSetFont(-1, $g_iHeight) ;, 400, 0, "Lucida Console")
    GUICtrlSetColor(-1, $g_iTextColor)
    GUICtrlSetBkColor(-1, $g_iBkColor)
;~  GUICtrlSetCursor(-1, 12) ; IDC_SIZENWSE ; ??
    GUICtrlSetResizing(-1, $GUI_DOCKSIZE + $GUI_DOCKRIGHT + $GUI_DOCKBOTTOM) ; Defines the resizing method
EndFunc   ;==>_Create_StatusBar
;---------------------------------------------------------------------------------------
Func _MyGUICtrlStatusBar_SetParts($hWnd, $aPartEdge) ; Function to set StatusBar parts
    Local $iParts = UBound($aPartEdge)
    Local $tParts = DllStructCreate("int[" & $iParts & "]")
    For $i = 0 To $iParts - 1
        DllStructSetData($tParts, 1, $aPartEdge[$i], $i + 1)
    Next
    DllCall("user32.dll", "lresult", "SendMessageW", "hwnd", $hWnd, "uint", $SB_SETPARTS, "wparam", $iParts, "struct*", $tParts)
    Return True
EndFunc   ;==>_MyGUICtrlStatusBar_SetParts
;---------------------------------------------------------------------------------------
Func WM_SIZE($hWnd, $iMsg, $wParam, $lParam) ; This function handles the resizing in real-time
    #forceref $iMsg, $wParam, $lParam

    If $hWnd = $g_hGui Then
        ; Get new Client Area dimensions
        Local $iW = BitAND($lParam, 0xFFFF)
        Local $iH = BitShift($lParam, 16)

        ; Resize StatusBar parts
        Local $aParts[3]
        $aParts[0] = Int($iW * $g_aRatioW[0])
        $aParts[1] = Int($iW * $g_aRatioW[1])
        $aParts[2] = $iW - $g_iGripW ; Ensure there's a $g_iGripW gap for the grip character

        _MyGUICtrlStatusBar_SetParts($g_hStatus, $aParts)
        _GUICtrlStatusBar_Resize($g_hStatus) ; Force the status bar to redraw itself

        ; Move the Grip Label precisely using WinAPI for zero lag
        Local $hGrip = GUICtrlGetHandle($g_idSizeGrip)
        _WinAPI_MoveWindow($hGrip, $iW - $g_iGripW, $iH - $g_iHeight - 3, $g_iGripW, $g_iHeight + 3, True)
    EndIf
    Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_SIZE
;---------------------------------------------------------------------------------------
Func WM_DRAWITEM($hWnd, $iMsg, $wParam, $lParam) ; Custom Text Drawing
    #forceref $hWnd, $iMsg, $wParam
    Local $tDRAWITEM = DllStructCreate("uint CtlType;uint CtlID;uint itemID;uint itemAction;uint itemState;hwnd hwndItem;handle hDC;long rcItem[4];ulong_ptr itemData", $lParam)

    If DllStructGetData($tDRAWITEM, "hwndItem") = $g_hStatus Then
        Local $hDC = DllStructGetData($tDRAWITEM, "hDC")
        Local $itemID = DllStructGetData($tDRAWITEM, "itemID")

        _WinAPI_SetTextColor($hDC, $g_iTextColor)
        _WinAPI_SetBkMode($hDC, 1) ; TRANSPARENT

        Local $tRect = DllStructCreate("long left;long top;long right;long bottom")
        DllStructSetData($tRect, "left", DllStructGetData($tDRAWITEM, "rcItem", 1) + 6)
        DllStructSetData($tRect, "top", DllStructGetData($tDRAWITEM, "rcItem", 2) + 3)
        DllStructSetData($tRect, "right", DllStructGetData($tDRAWITEM, "rcItem", 3))
        DllStructSetData($tRect, "bottom", DllStructGetData($tDRAWITEM, "rcItem", 4))

        _WinAPI_DrawText($hDC, $g_aText[$itemID], $tRect, $DT_LEFT)
        Return True
    EndIf
    Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_DRAWITEM
;---------------------------------------------------------------------------------------
Func ApplyDPI() ; Apply DPI
    DllCall("User32.dll", "bool", "SetProcessDpiAwarenessContext", "HWND", -2)
    Local $hAutoIt = WinGetHandle(AutoItWinGetTitle())
    $iDPI = _WinAPI_GetDpiForWindow($hAutoIt) / 96
    If @error Or $iDPI <= 0 Then $iDPI = 1
EndFunc   ;==>ApplyDPI
;---------------------------------------------------------------------------------------
Func _WinAPI_GetDpiForWindow($hWnd) ; Get Dpi
    Local $aResult = DllCall("user32.dll", "uint", "GetDpiForWindow", "hwnd", $hWnd)
    If @error Then Return 96
    Return $aResult[0]
EndFunc   ;==>_WinAPI_GetDpiForWindow
;---------------------------------------------------------------------------------------

 

Edited by ioa747
chance to $SM_CXVSCROLL

I know that I know nothing

Posted
16 hours ago, ioa747 said:

with sacrifice ?  :)

This is a really cool idea. Thanks for sharing. :)

Using fonts for the texture is nice because it's quite easy but also scales very well.

7 hours ago, argumentum said:

...all you need is an 8k monitor. If the wife ask about the expense, you say "honey: was for science", and she'll say "ok, that makes sense" and you'll be off the hook :D

If I ask for that I may be sleeping on the couch. 🙃

I ended up extracting all of the gripper images (PNG) from the aero.msstyles file for each of the resolutions to confirm my initial measurements but also to get the measurements for 200% and higher scaling.

Although that makes me wonder now... I wonder if I could just add those PNG images (1 KB each x 8 images) to the compiled binary, load them and place over the same area of the statusbar that we are drawing over with the CreateDots function. I would probably convert them to ICO so that they can be 1 single file with a layer for each DPI scale.

Posted (edited)
23 hours ago, WildByDesign said:
        Case 2      ; 200% scaling
            $iDotSize = 4
            $iDotSpace = $iDotSize - 1
            $iDotFrame = 1
            Local $a[6][2] = [[3,7], [3,5], [3,3], [5,5], [5,3], [7,3]]
        Case Else

8k can easily use 500%. Thinking of after 200% "screw you buddy", ain't nice.
As long as odd percentages look good ( 125% & 175% ) in your monitor, it should look the same in greater scaling like 225%

All tho, if you could get yourself a 4k monitor ( they are quite inexpensive nowadays compared to some years ago ) it would be good.

 

Edited by argumentum
English

Follow the link to my code contribution ( and other things too ).
FAQ - Please Read Before Posting.
autoit_scripter_blue_userbar.png

Posted
On 1/3/2026 at 10:22 PM, WildByDesign said:
$iDPI = Round(_WinAPI_GetDpiForWindow(WinGetHandle(AutoItWinGetTitle())) / 96, 2)

I was actually quite proud of myself yesterday for the simple creativity of this line. Getting the DPI from the hidden AutoIt window works well and it is easier to get the handle for it with a small amount of code. This way, you can have the DPI scale before the GUI launches.

However, this proved flawed. It worked yesterday. But I noticed today that it was working only about 5-10% of the time. The reason for that is quite simple: The hidden AutoIt window isn't always created yet at that point.

I noticed that if I put Sleep(50) above that line, it works every time. But timing changes like that aren't always great because it may not work the same on all hardware.

I'm going to fix the DPI stuff today (already have on my machine) and I will finish the CreateDots creation for 200% scaling and higher. Then I will share an updated script later. :)

Posted (edited)

Can anyone with the ability to test at 200% scaling and higher please test something for me?

I made it so that the GUI has a button to hide/show the fake sizebox to make it easier to confirm whether the sizebox dot size, spacing and alignment is correct or not. When you hide the fake sizebox, it will show the genuine Windows sizebox/sizegrip for comparison.

I have already confirmed 100%, 125%, 150% and 175%.

I've added 200%, 250%, 300% and 400% and need those confirmed, if possible.

What I've been doing is simply doing a screenshot with the fake sizebox showing and a screenshot of the fake sizebox hidden. Then I put them into an image editing program on two different layers, zoom in and show/hide one of the layers to see whether or not the dot size, spacing and alignment matches. Or if you share the screenshots here, I can compare and make any adjustments to the CreateDots function.

Once everything is working right, I should be able to combine many of the lines in the CreateDots function to make it more compact.

Thank you! :)

EDIT: I should also mention that the GUI does not react to DPI changes dynamically. So when changing to another DPI scale to test, you will have to close the GUI and run the script again.

#include <GDIPlus.au3>
#include <GUIConstantsEx.au3>
#include <GuiStatusBar.au3>
#include <StaticConstants.au3>
#include <WinAPIGdi.au3>
#include <WinAPIRes.au3>
#include <WinAPISysWin.au3>
#include <WinAPITheme.au3>
#include <WindowsConstants.au3>

Opt("MustDeclareVars", 1)

Global $g_hGui, $g_hSizebox, $g_hOldProc, $g_hStatus, $g_iHeight, $g_aText, $g_aRatioW, $g_iBkColor, $g_iTextColor, $g_hDots
Global $g_hBrush

; set base DPI scale value and apply DPI
Global $idChangeText
Global $DPI_AWARENESS_CONTEXT_SYSTEM_AWARE = -2
Global $iDPI = 1
ApplyDPI()

Func ApplyDPI()
    ; apply System DPI awareness and calculate factor
    _WinAPI_SetThreadDpiAwarenessContext($DPI_AWARENESS_CONTEXT_SYSTEM_AWARE)
    If Not @error Then
        $iDPI = Round(_WinAPI_GetDpiForSystem() / 96, 2)
        If @error Then $iDPI = 1
    Else
        $iDPI = 1
    EndIf

    ; simulate 200% scaling for sizebox
    ;$iDPI = 2
    ConsoleWrite("DPI scale: " & $iDPI & @CRLF)
EndFunc

Example()

;==============================================
Func Example()

    _GDIPlus_Startup()

    Local Const $SBS_SIZEBOX = 0x08, $SBS_SIZEGRIP = 0x10
    Local $iW = 320 * $iDPI, $iH = 100 * $iDPI
    Dim $g_iBkColor = _WinAPI_SwitchColor(_WinAPI_GetSysColor($COLOR_BTNFACE)), $g_iTextColor = 0x000000

    $g_hGui = GUICreate("Resize corner", $iW, $iH, -1, -1, $WS_OVERLAPPEDWINDOW)
    GUISetBkColor($g_iBkColor)

    ;-----------------
    ; Create a sizebox window (Scrollbar class) BEFORE creating the StatusBar control
    $g_hSizebox = _WinAPI_CreateWindowEx(0, "Scrollbar", "", $WS_CHILD + $WS_VISIBLE + $SBS_SIZEBOX, _
        0, 0, 0, 0, $g_hGui) ; $SBS_SIZEBOX or $SBS_SIZEGRIP

    ; Subclass the sizebox (by changing the window procedure associated with the Scrollbar class)
    Local $hProc = DllCallbackRegister('ScrollbarProc', 'lresult', 'hwnd;uint;wparam;lparam')
    $g_hOldProc = _WinAPI_SetWindowLong($g_hSizebox, $GWL_WNDPROC, DllCallbackGetPtr($hProc))

    Local $hCursor = _WinAPI_LoadCursor(0, $OCR_SIZENWSE)
    _WinAPI_SetClassLongEx($g_hSizebox, -12, $hCursor) ; $GCL_HCURSOR = -12

    $g_hBrush = _WinAPI_CreateSolidBrush($g_iBkColor)

    ;-----------------
    $g_hStatus = _GUICtrlStatusBar_Create($g_hGui, -1, "", $WS_CLIPSIBLINGS) ; ClipSiblings style +++
    Local $aParts[3] = [90, 180, -1]
    If $aParts[Ubound($aParts) - 1] = -1 Then $aParts[Ubound($aParts) - 1] = $iW ; client width size
    _MyGUICtrlStatusBar_SetParts($g_hStatus, $aParts)

    Dim $g_aText[Ubound($aParts)] = [" ", " ", " "]
    Dim $g_aRatioW[Ubound($aParts)]
    For $i = 0 To UBound($g_aText) - 1
        _GUICtrlStatusBar_SetText($g_hStatus, "", $i, $SBT_OWNERDRAW + $SBT_NOBORDERS)
        $g_aRatioW[$i] = $aParts[$i] / $iW
    Next

    $idChangeText = GUICtrlCreateButton("Hide Fake Sizebox", 110 * $iDPI, 25 * $iDPI, -1, -1)

    ; ensure that sizebox has Explorer theme with gripper dots
    _WinAPI_SetWindowTheme($g_hStatus, "Explorer")

    $g_iHeight = _GUICtrlStatusBar_GetHeight($g_hStatus) + 0 ; change the constant (+3) if necessary
    $g_hDots = CreateDots($g_iHeight, $g_iHeight, 0xFF000000 + $g_iBkColor, 0xFF000000 + $g_iTextColor)

    GUIRegisterMsg($WM_SIZE, "WM_SIZE")
    GUIRegisterMsg($WM_MOVE, "WM_MOVE")
    GUIRegisterMsg($WM_DRAWITEM, "WM_DRAWITEM")

    ; get rid of the focus rectangle dots on button
    GUICtrlSendMsg($idChangeText, $WM_CHANGEUISTATE, 65537, 0)

    ; set title with DPI scaling info
    WinSetTitle($g_hGui, "", $iDPI * 100 & "% DPI Scale")

    GUISetState()

    While 1
        Switch GUIGetMsg()
            Case $GUI_EVENT_CLOSE
                ExitLoop

            Case $idChangeText
                _ShowHideSizebox()
        EndSwitch
    WEnd

    _GDIPlus_BitmapDispose($g_hDots)
    _GUICtrlStatusBar_Destroy($g_hStatus)
    _WinAPI_DestroyCursor($hCursor)
    _WinAPI_DeleteObject($g_hBrush)
    _WinAPI_SetWindowLong($g_hSizebox, $GWL_WNDPROC, $g_hOldProc)
    DllCallbackFree($hProc)
    _GDIPlus_Shutdown()
EndFunc   ;==>Example

;==============================================
Func ScrollbarProc($hWnd, $iMsg, $wParam, $lParam) ; Andreik

    If $iMsg = $WM_PAINT Then
        Local $tPAINTSTRUCT
        Local $hDC = _WinAPI_BeginPaint($hWnd, $tPAINTSTRUCT)
        Local $iWidth = DllStructGetData($tPAINTSTRUCT, 'rPaint', 3) - DllStructGetData($tPAINTSTRUCT, 'rPaint', 1)
        Local $iHeight = DllStructGetData($tPAINTSTRUCT, 'rPaint', 4) - DllStructGetData($tPAINTSTRUCT, 'rPaint', 2)
        Local $hGraphics = _GDIPlus_GraphicsCreateFromHDC($hDC)
        _GDIPlus_GraphicsDrawImageRect($hGraphics, $g_hDots, 0, 0, $iWidth, $iHeight)
        _GDIPlus_GraphicsDispose($hGraphics)
        _WinAPI_EndPaint($hWnd, $tPAINTSTRUCT)
        Return 0
    EndIf
    Return _WinAPI_CallWindowProc($g_hOldProc, $hWnd, $iMsg, $wParam, $lParam)
EndFunc   ;==>ScrollbarProc

;==============================================
Func CreateDots($iWidth, $iHeight, $iBackgroundColor, $iDotsColor) ; Andreik
    Local $iDotSize, $iDotSpace, $iDotFrame
    Switch $iDPI
        ;       Dot Size    Spacing     From Right  From Bottom Confirmed
        ; 100%      2           1           2           2           yes
        ; 125%      3           1           2           2           yes
        ; 150%      3           1           2           2           yes
        ; 175%      3           1           2           2           not existing
        ; 200%      4           2           4           4           ?
        ; 250%      5           2           5           5           ?
        ; 300%      6           3           6           6           ?
        ; 400%      8           4           8           8           ?
        Case 1      ; 100% scaling
            $iDotSize = 2
            $iDotSpace = $iDotSize - 1  ; ensures that dots have only 1 pixel of space between
            $iDotFrame = -1             ; controls the distance from frame
            Local $a[6][2] = [[3,9], [3,6], [3,3], [6,6], [6,3], [9,3]]
        Case 1.25   ; 125% scaling
            $iDotSize = 3
            $iDotSpace = $iDotSize - 1
            $iDotFrame = 1
            Local $a[6][2] = [[3,7], [3,5], [3,3], [5,5], [5,3], [7,3]]
        Case 1.5    ; 150% scaling
            $iDotSize = 3
            $iDotSpace = $iDotSize - 1
            $iDotFrame = 1
            Local $a[6][2] = [[3,7], [3,5], [3,3], [5,5], [5,3], [7,3]]
        Case 1.75   ; 175% scaling
            $iDotSize = 3
            $iDotSpace = $iDotSize - 1
            $iDotFrame = 1
            Local $a[6][2] = [[3,7], [3,5], [3,3], [5,5], [5,3], [7,3]]
        Case 2      ; 200% scaling
            $iDotSize = 4
            $iDotSpace = $iDotSize - 1
            $iDotFrame = 1
            Local $a[6][2] = [[3,7], [3,5], [3,3], [5,5], [5,3], [7,3]]
        Case 2.5    ; 250% scaling
            $iDotSize = 5
            $iDotSpace = $iDotSize - 1
            $iDotFrame = 1
            Local $a[6][2] = [[3,7], [3,5], [3,3], [5,5], [5,3], [7,3]]
        Case 3      ; 300% scaling
            $iDotSize = 6
            $iDotSpace = $iDotSize - 1
            $iDotFrame = 1
            Local $a[6][2] = [[3,7], [3,5], [3,3], [5,5], [5,3], [7,3]]
        Case 4      ; 400% scaling
            $iDotSize = 8
            $iDotSpace = $iDotSize - 1
            $iDotFrame = 1
            Local $a[6][2] = [[3,7], [3,5], [3,3], [5,5], [5,3], [7,3]]
        Case Else
            $iDotSize = 1
            $iDotSpace = $iDotSize - 1
            $iDotFrame = 1
            Local $a[6][2] = [[3,7], [3,5], [3,3], [5,5], [5,3], [7,3]]
    EndSwitch
    Local $hBitmap = _GDIPlus_BitmapCreateFromScan0($iWidth, $iHeight)
    Local $hGraphics = _GDIPlus_ImageGetGraphicsContext($hBitmap)
    Local $hBrush = _GDIPlus_BrushCreateSolid($iDotsColor)
    _GDIPlus_GraphicsClear($hGraphics, $iBackgroundColor)
    For $i = 0 To UBound($a) - 1
        _GDIPlus_GraphicsFillRect($hGraphics, $iWidth - ($iDotSpace * $a[$i][0]) + $iDotFrame, $iHeight - ($iDotSpace * $a[$i][1]) + $iDotFrame, $iDotSize, $iDotSize, $hBrush)
    Next
    _GDIPlus_BrushDispose($hBrush)
    _GDIPlus_GraphicsDispose($hGraphics)
    Return $hBitmap
EndFunc   ;==>CreateDots

;==============================================
Func _MyGUICtrlStatusBar_SetParts($hWnd, $aPartEdge) ; Pixelsearch

    If Not IsArray($aPartEdge) Then Return False
    Local $iParts = UBound($aPartEdge)
    Local $tParts = DllStructCreate("int[" & $iParts & "]")
    For $i = 0 To $iParts - 1
        DllStructSetData($tParts, 1, $aPartEdge[$i], $i + 1)
    Next
    DllCall("user32.dll", "lresult", "SendMessageW", "hwnd", $hWnd, "uint", $SB_SETPARTS, "wparam", $iParts, "struct*", $tParts)
    _GUICtrlStatusBar_Resize($hWnd)
    Return True
EndFunc   ;==>_MyGUICtrlStatusBar_SetParts

;==============================================
Func WM_SIZE($hWnd, $iMsg, $wParam, $lParam) ; Pixelsearch
    #forceref $iMsg, $wParam, $lParam

    If $hWnd = $g_hGUI Then
        Local Static $bIsSizeBoxShown = True
        Local $aSize = WinGetClientSize($g_hGui)
        Local $aGetParts = _GUICtrlStatusBar_GetParts($g_hStatus)
        Local $aParts[$aGetParts[0]]
        For $i = 0 To $aGetParts[0] - 1
            $aParts[$i] = Int($aSize[0] * $g_aRatioW[$i])
        Next
        If BitAND(WinGetState($g_hGui), $WIN_STATE_MAXIMIZED) Then
            _GUICtrlStatusBar_SetParts($g_hStatus, $aParts) ; set parts until GUI right border (AutoIt function forces it)
            _WinAPI_ShowWindow($g_hSizebox, @SW_HIDE)
            $bIsSizeBoxShown = False
        Else
            If $g_aRatioW[UBound($aParts) -1] <> 1 Then $aParts[UBound($aParts) -1] = $aSize[0] - $g_iHeight ; right size of right part stuck on sizebox (no gap)
            _MyGUICtrlStatusBar_SetParts($g_hStatus, $aParts) ; set parts until sizebox (see preceding line) or until GUI right border
            WinMove($g_hSizebox, "", $aSize[0] - $g_iHeight, $aSize[1] - $g_iHeight, $g_iHeight, $g_iHeight)
            If Not $bIsSizeBoxShown Then
                _WinAPI_ShowWindow($g_hSizebox, @SW_SHOW)
                $bIsSizeBoxShown = True
            EndIf
        EndIf
    EndIf
    Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_SIZE

;==============================================
Func WM_MOVE($hWnd, $iMsg, $wParam, $lParam)
    #forceref $iMsg, $wParam, $lParam

    If $hWnd = $g_hGUI Then
        _WinAPI_RedrawWindow($g_hSizebox)
    EndIf
    Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_MOVE

;==============================================
Func WM_DRAWITEM($hWnd, $iMsg, $wParam, $lParam) ; Kafu
    #forceref $hWnd, $iMsg, $wParam

    Local Static $tagDRAWITEM = "uint CtlType;uint CtlID;uint itemID;uint itemAction;uint itemState;hwnd hwndItem;handle hDC;long rcItem[4];ulong_ptr itemData"
    Local $tDRAWITEM = DllStructCreate($tagDRAWITEM, $lParam)
    If $tDRAWITEM.hwndItem <> $g_hStatus Then Return $GUI_RUNDEFMSG ; only process the statusbar

    Local $itemID = $tDRAWITEM.itemID ; status bar part number : 0 if simple bar (or 0, 1, 2... if multi parts)
    Local $hDC = $tDRAWITEM.hDC
    Local $tRect = DllStructCreate("long left;long top;long right;long bottom", DllStructGetPtr($tDRAWITEM, "rcItem"))
    ;_WinAPI_FillRect($hDC, DllStructGetPtr($tRect), $g_hBrush) ; backgound color
    _WinAPI_SetTextColor($hDC, $g_iTextColor) ; text color
    _WinAPI_SetBkMode($hDC, $TRANSPARENT)
    DllStructSetData($tRect, "top", $tRect.top + 1)
    DllStructSetData($tRect, "left", $tRect.left + 1)
    _WinAPI_DrawText($hDC, $g_aText[$itemID], $tRect, $DT_LEFT)

    Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_DRAWITEM

Func _WinAPI_SetThreadDpiAwarenessContext($DPI_AWARENESS_CONTEXT_value) ; UEZ
    Local $aResult = DllCall("user32.dll", "uint", "SetThreadDpiAwarenessContext", @AutoItX64 ? "int64" : "int", $DPI_AWARENESS_CONTEXT_value) ;requires Win10 v1703+ / Windows Server 2016+
    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_SetThreadDpiAwarenessContext

Func _WinAPI_GetDpiForSystem() ; UEZ
    Local $aResult = DllCall("user32.dll", "uint", "GetDpiForSystem") ;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_GetDpiForSystem

Func _ShowHideSizebox()
    If _WinAPI_IsWindowVisible ($g_hSizebox) Then
        _WinAPI_ShowWindow($g_hSizebox, @SW_HIDE)
        GUICtrlSetData($idChangeText, "Show Fake Sizebox")
    ElseIf Not _WinAPI_IsWindowVisible ($g_hSizebox) Then
        _WinAPI_ShowWindow($g_hSizebox, @SW_SHOW)
        GUICtrlSetData($idChangeText, "Hide Fake Sizebox")
    EndIf
EndFunc

 

Edited by WildByDesign
Posted (edited)
Case 2 To 2.49
...
Case 2.5 To 2.99
...
Case 3 To ...
2 hours ago, argumentum said:

4k at 225%

That looks pretty good. Thanks.

I didn’t even realize that there was a 225%.  The msstyles file doesn’t have resources for 175% or 225% and likely a few others but probably stretches the closest image resources. I’ll probably need to do something like:

EDIT: Ahh. Silly phone always puts the code box at the top. 🙃

Edited by WildByDesign
Posted

Alright, here we go. The following example has the following features:

  • Dark mode statusbar with modern theme applied
  • Updated CreateDots function with full DPI support
    • Dot size, spacing and alignment are identical to gripper dots from light mode Explorer theme
    • Gripper dots tested up to 400% DPI scaling

Somehow it took me 3 days to complete this. But I am finally satisfied now. 😎

#include <GDIPlus.au3>
#include <GUIConstantsEx.au3>
#include <GuiStatusBar.au3>
#include <StaticConstants.au3>
#include <WinAPIGdi.au3>
#include <WinAPIRes.au3>
#include <WinAPISysWin.au3>
#include <WinAPITheme.au3>
#include <WindowsConstants.au3>

Opt("MustDeclareVars", 1)

Global $g_hGui, $g_hSizebox, $g_hOldProc, $g_hStatus, $g_iHeight, $g_aText, $g_aRatioW, $g_iBkColor, $g_iTextColor, $g_hDots
Global $g_hBrush

; set base DPI scale value and apply DPI
Global $DPI_AWARENESS_CONTEXT_SYSTEM_AWARE = -2
Global $iDPI = 1
ApplyDPI()

Func ApplyDPI()
    ; apply System DPI awareness and calculate factor
    _WinAPI_SetThreadDpiAwarenessContext($DPI_AWARENESS_CONTEXT_SYSTEM_AWARE)
    If Not @error Then
        $iDPI = Round(_WinAPI_GetDpiForSystem() / 96, 2)
        If @error Then $iDPI = 1
    Else
        $iDPI = 1
    EndIf
EndFunc

Example()

;==============================================
Func Example()

    _GDIPlus_Startup()

    Local Const $SBS_SIZEBOX = 0x08, $SBS_SIZEGRIP = 0x10
    Local $iW = 320 * $iDPI, $iH = 100 * $iDPI
    Dim $g_iBkColor = 0x202020, $g_iTextColor = 0xFFFFFF

    $g_hGui = GUICreate("CreateDots DPI", $iW, $iH, -1, -1, $WS_OVERLAPPEDWINDOW)
    GUISetBkColor(0x181818)

    ;-----------------
    ; Create a sizebox window (Scrollbar class) BEFORE creating the StatusBar control
    $g_hSizebox = _WinAPI_CreateWindowEx(0, "Scrollbar", "", $WS_CHILD + $WS_VISIBLE + $SBS_SIZEBOX, _
        0, 0, 0, 0, $g_hGui) ; $SBS_SIZEBOX or $SBS_SIZEGRIP

    ; Subclass the sizebox (by changing the window procedure associated with the Scrollbar class)
    Local $hProc = DllCallbackRegister('ScrollbarProc', 'lresult', 'hwnd;uint;wparam;lparam')
    $g_hOldProc = _WinAPI_SetWindowLong($g_hSizebox, $GWL_WNDPROC, DllCallbackGetPtr($hProc))

    Local $hCursor = _WinAPI_LoadCursor(0, $OCR_SIZENWSE)
    _WinAPI_SetClassLongEx($g_hSizebox, -12, $hCursor) ; $GCL_HCURSOR = -12

    $g_hBrush = _WinAPI_CreateSolidBrush($g_iBkColor)

    ;-----------------
    $g_hStatus = _GUICtrlStatusBar_Create($g_hGui, -1, "", $WS_CLIPSIBLINGS) ; ClipSiblings style +++
    Local $aParts[3] = [90, 180, -1]
    If $aParts[Ubound($aParts) - 1] = -1 Then $aParts[Ubound($aParts) - 1] = $iW ; client width size
    _MyGUICtrlStatusBar_SetParts($g_hStatus, $aParts)

    Dim $g_aText[Ubound($aParts)] = ["Part 0", "Part 1", "Part 2"]
    Dim $g_aRatioW[Ubound($aParts)]
    For $i = 0 To UBound($g_aText) - 1
        _GUICtrlStatusBar_SetText($g_hStatus, "", $i, $SBT_OWNERDRAW + $SBT_NOBORDERS)
        $g_aRatioW[$i] = $aParts[$i] / $iW
    Next

    $g_iHeight = _GUICtrlStatusBar_GetHeight($g_hStatus) + 3 ; change the constant (+3) if necessary
    $g_hDots = CreateDots($g_iHeight, $g_iHeight, 0xFF000000 + $g_iBkColor, 0xFF000000 + $g_iTextColor)

    GUIRegisterMsg($WM_SIZE, "WM_SIZE")
    GUIRegisterMsg($WM_MOVE, "WM_MOVE")
    GUIRegisterMsg($WM_DRAWITEM, "WM_DRAWITEM")

    ; apply dark mode to titlebar and statusbar
    _WinAPI_SetWindowTheme($g_hStatus, "DarkMode", "ExplorerStatusBar")
    _WinAPI_DwmSetWindowAttribute($g_hGui, $DWMWA_USE_IMMERSIVE_DARK_MODE, True)
    GUISetState()

    While 1
        Switch GUIGetMsg()
            Case $GUI_EVENT_CLOSE
                ExitLoop

        EndSwitch
    WEnd

    _GDIPlus_BitmapDispose($g_hDots)
    _GUICtrlStatusBar_Destroy($g_hStatus)
    _WinAPI_DestroyCursor($hCursor)
    _WinAPI_DeleteObject($g_hBrush)
    _WinAPI_SetWindowLong($g_hSizebox, $GWL_WNDPROC, $g_hOldProc)
    DllCallbackFree($hProc)
    _GDIPlus_Shutdown()
EndFunc   ;==>Example

;==============================================
Func ScrollbarProc($hWnd, $iMsg, $wParam, $lParam) ; Andreik

    If $iMsg = $WM_PAINT Then
        Local $tPAINTSTRUCT
        Local $hDC = _WinAPI_BeginPaint($hWnd, $tPAINTSTRUCT)
        Local $iWidth = DllStructGetData($tPAINTSTRUCT, 'rPaint', 3) - DllStructGetData($tPAINTSTRUCT, 'rPaint', 1)
        Local $iHeight = DllStructGetData($tPAINTSTRUCT, 'rPaint', 4) - DllStructGetData($tPAINTSTRUCT, 'rPaint', 2)
        Local $hGraphics = _GDIPlus_GraphicsCreateFromHDC($hDC)
        _GDIPlus_GraphicsDrawImageRect($hGraphics, $g_hDots, 0, 0, $iWidth, $iHeight)
        _GDIPlus_GraphicsDispose($hGraphics)
        _WinAPI_EndPaint($hWnd, $tPAINTSTRUCT)
        Return 0
    EndIf
    Return _WinAPI_CallWindowProc($g_hOldProc, $hWnd, $iMsg, $wParam, $lParam)
EndFunc   ;==>ScrollbarProc

;==============================================
Func CreateDots($iWidth, $iHeight, $iBackgroundColor, $iDotsColor) ; Andreik
    Local $iDotSize, $iDotSpace, $iDotFrame
    Local $iDPIpct = $iDPI * 100
    Switch $iDPIpct
        ;       Dot Size    Spacing     From Right  From Bottom Confirmed
        ; 100%      2           1           2           2           yes
        ; 125%      3           1           2           2           yes
        ; 150%      3           1           2           2           yes
        ; 175%      3           1           2           2           yes
        ; 200%      4           2           4           4           yes
        ; 250%      5           2           5           5           yes
        ; 300%      6           3           6           6           yes
        ; 400%      8           4           8           8           yes
        Case 100
            $iDotSize = 2
            $iDotSpace = $iDotSize - 0.5    ; gives some control over the spacing between dots
            $iDotFrame = 0.5                ; gives some control over the spacing from frame
        Case 125 To 175
            $iDotSize = 3
            $iDotSpace = $iDotSize - 1
            $iDotFrame = 1
        Case 200 To 225
            $iDotSize = 4
            $iDotSpace = $iDotSize - 1
            $iDotFrame = 1
        Case 250 To 275
            $iDotSize = 5
            $iDotSpace = $iDotSize - 1.5
            $iDotFrame = 0
        Case 300 To 375
            $iDotSize = 6
            $iDotSpace = $iDotSize - 1.5
            $iDotFrame = 1
        Case 400 To 500
            $iDotSize = 8
            $iDotSpace = $iDotSize - 2
            $iDotFrame = 2
        Case Else
            $iDotSize = 3
            $iDotSpace = $iDotSize - 1
            $iDotFrame = 1
    EndSwitch

    Local $a[6][2] = [[3,7], [3,5], [3,3], [5,5], [5,3], [7,3]]
    Local $hBitmap = _GDIPlus_BitmapCreateFromScan0($iWidth, $iHeight)
    Local $hGraphics = _GDIPlus_ImageGetGraphicsContext($hBitmap)
    Local $hBrush = _GDIPlus_BrushCreateSolid($iDotsColor)
    _GDIPlus_GraphicsClear($hGraphics, $iBackgroundColor)
    For $i = 0 To UBound($a) - 1
        _GDIPlus_GraphicsFillRect($hGraphics, $iWidth - ($iDotSpace * $a[$i][0]) + $iDotFrame, $iHeight - ($iDotSpace * $a[$i][1]) + $iDotFrame, $iDotSize, $iDotSize, $hBrush)
    Next
    _GDIPlus_BrushDispose($hBrush)
    _GDIPlus_GraphicsDispose($hGraphics)
    Return $hBitmap
EndFunc   ;==>CreateDots

;==============================================
Func _MyGUICtrlStatusBar_SetParts($hWnd, $aPartEdge) ; Pixelsearch

    If Not IsArray($aPartEdge) Then Return False
    Local $iParts = UBound($aPartEdge)
    Local $tParts = DllStructCreate("int[" & $iParts & "]")
    For $i = 0 To $iParts - 1
        DllStructSetData($tParts, 1, $aPartEdge[$i], $i + 1)
    Next
    DllCall("user32.dll", "lresult", "SendMessageW", "hwnd", $hWnd, "uint", $SB_SETPARTS, "wparam", $iParts, "struct*", $tParts)
    _GUICtrlStatusBar_Resize($hWnd)
    Return True
EndFunc   ;==>_MyGUICtrlStatusBar_SetParts

;==============================================
Func WM_SIZE($hWnd, $iMsg, $wParam, $lParam) ; Pixelsearch
    #forceref $iMsg, $wParam, $lParam

    If $hWnd = $g_hGUI Then
        Local Static $bIsSizeBoxShown = True
        Local $aSize = WinGetClientSize($g_hGui)
        Local $aGetParts = _GUICtrlStatusBar_GetParts($g_hStatus)
        Local $aParts[$aGetParts[0]]
        For $i = 0 To $aGetParts[0] - 1
            $aParts[$i] = Int($aSize[0] * $g_aRatioW[$i])
        Next
        If BitAND(WinGetState($g_hGui), $WIN_STATE_MAXIMIZED) Then
            _GUICtrlStatusBar_SetParts($g_hStatus, $aParts) ; set parts until GUI right border (AutoIt function forces it)
            _WinAPI_ShowWindow($g_hSizebox, @SW_HIDE)
            $bIsSizeBoxShown = False
        Else
            If $g_aRatioW[UBound($aParts) -1] <> 1 Then $aParts[UBound($aParts) -1] = $aSize[0] - $g_iHeight ; right size of right part stuck on sizebox (no gap)
            _MyGUICtrlStatusBar_SetParts($g_hStatus, $aParts) ; set parts until sizebox (see preceding line) or until GUI right border
            WinMove($g_hSizebox, "", $aSize[0] - $g_iHeight, $aSize[1] - $g_iHeight, $g_iHeight, $g_iHeight)
            If Not $bIsSizeBoxShown Then
                _WinAPI_ShowWindow($g_hSizebox, @SW_SHOW)
                $bIsSizeBoxShown = True
            EndIf
        EndIf
    EndIf
    Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_SIZE

;==============================================
Func WM_MOVE($hWnd, $iMsg, $wParam, $lParam)
    #forceref $iMsg, $wParam, $lParam

    If $hWnd = $g_hGUI Then
        _WinAPI_RedrawWindow($g_hSizebox)
    EndIf
    Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_MOVE

;==============================================
Func WM_DRAWITEM($hWnd, $iMsg, $wParam, $lParam) ; Kafu
    #forceref $hWnd, $iMsg, $wParam

    Local Static $tagDRAWITEM = "uint CtlType;uint CtlID;uint itemID;uint itemAction;uint itemState;hwnd hwndItem;handle hDC;long rcItem[4];ulong_ptr itemData"
    Local $tDRAWITEM = DllStructCreate($tagDRAWITEM, $lParam)
    If $tDRAWITEM.hwndItem <> $g_hStatus Then Return $GUI_RUNDEFMSG ; only process the statusbar

    Local $itemID = $tDRAWITEM.itemID ; status bar part number : 0 if simple bar (or 0, 1, 2... if multi parts)
    Local $hDC = $tDRAWITEM.hDC
    Local $tRect = DllStructCreate("long left;long top;long right;long bottom", DllStructGetPtr($tDRAWITEM, "rcItem"))
    _WinAPI_FillRect($hDC, DllStructGetPtr($tRect), $g_hBrush) ; backgound color
    _WinAPI_SetTextColor($hDC, $g_iTextColor) ; text color
    _WinAPI_SetBkMode($hDC, $TRANSPARENT)
    DllStructSetData($tRect, "top", $tRect.top + 1)
    DllStructSetData($tRect, "left", $tRect.left + 1)
    _WinAPI_DrawText($hDC, $g_aText[$itemID], $tRect, $DT_LEFT)

    Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_DRAWITEM

Func _WinAPI_SetThreadDpiAwarenessContext($DPI_AWARENESS_CONTEXT_value) ; UEZ
    Local $aResult = DllCall("user32.dll", "uint", "SetThreadDpiAwarenessContext", @AutoItX64 ? "int64" : "int", $DPI_AWARENESS_CONTEXT_value) ;requires Win10 v1703+ / Windows Server 2016+
    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_SetThreadDpiAwarenessContext

Func _WinAPI_GetDpiForSystem() ; UEZ
    Local $aResult = DllCall("user32.dll", "uint", "GetDpiForSystem") ;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_GetDpiForSystem

 

Posted
8 hours ago, ioa747 said:

and a little further down you will find  "my homework :)

Very nice, thank you for sharing. :)

I wasn't familiar with the _WinAPI_SystemParametersInfo function before but after reading the msdn page I see how powerful it is. Your DPI_Scaling_Utility is definitely a keeper. I like how you provide GUI and CLI options.

  • 2 weeks later...
Posted
On 4/23/2025 at 5:28 AM, pixelsearch said:
$g_iHeight = _GUICtrlStatusBar_GetHeight($g_hStatus) + 3 ; change the constant (+3) if necessary

I've been having some strange measurement issues in several of my GUI projects that I noticed. After digging into it some more, it turns out that the results from the _GUICtrlStatusBar_GetHeight function are wildly inaccurate.

At first, I thought that I could simply multiply the value by the current DPI scale value. But that was still not accurate. I don't know why that function provides the wrong results because I don't fully understand it.

However, I do have a solution. As soon as I switched to this other method, all of my GUI mismeasurements were solved. This also provides the perfect results under all DPI scale options without having to do any multiplications on it.

Local $aStatusHeight = WinGetPos($g_hStatus)
$g_iHeight = $aStatusHeight[3]

 

  • 1 month later...
Posted (edited)

@pixelsearch I have been thinking recently about turning your ownerdrawn statusbar into a UDF. It is one of the more tricky solutions to implement into an existing GUI. Starting with a new GUI is not too bad though. But I was thinking about making a solution that would automatically detect and subclass the statusbar. It would be used together with the GUIDarkTheme UDF but also I would design it so that it could be used by itself as well.

But before I get started, I decided to check and see how Notepad++ handles their dark mode statusbar since they have some of the best win32-dark mode subclassing techniques. Keep in mind that they do not remove the theme from their statusbar. So what happens in that case is you get an empty square in the spot where the SIZEGRIP would normally be. So Notepad++ would therefore have to have some method which draws/paints this part.

What I noticed seems quite interesting (from StatusBar.cpp )

In general, you can search that file for all instances of "sizegrip". But I found this interesting part here:

if (isSizeGrip)
{
	pStatusBarInfo->ensureTheme(hWnd);
	SIZE gripSize{};
	RECT rc{};
	::GetClientRect(hWnd, &rc);
	GetThemePartSize(pStatusBarInfo->hTheme, hdc, SP_GRIPPER, 0, &rc, TS_DRAW, &gripSize);
	rc.left = rc.right - gripSize.cx;
	rc.top = rc.bottom - gripSize.cy;
	DrawThemeBackground(pStatusBarInfo->hTheme, hdc, SP_GRIPPER, 0, &rc, nullptr);
}

Instead of measuring and painting individual dots, they seem to access SP_GRIPPER part from the theme resources (aero.msstyles). I had assumed in the past that DrawThemeBackground simply painted a theme color. But now I am wondering if it's actually doing more then that. We have access to all of these functions in AutoIt. So I am starting to wonder if this may be the more appropriate choice instead of measuring and painting the dots. This would access the theme resources available on the system (and future OS versions in case of changes).

What do you think of this?

Edited by WildByDesign
Posted

Here is something:

DllCall("user32.dll", "bool", "SetProcessDpiAwarenessContext", @AutoItX64 ? "int64" : "int", -2)

#include <FontConstants.au3>
#include <GUIConstantsEx.au3>
#include <SendMessage.au3>
#include <StaticConstants.au3>
#include <WinAPIGdi.au3>
#include <WinAPIGdiDC.au3>
#include <WinAPIHObj.au3>
#include <WinAPIMisc.au3>
#include <WinAPISysWin.au3>
#include <WinAPITheme.au3>
#include <WindowsSysColorConstants.au3>

_Example()

Func _Example()
    ; Create GUI
    Local $hForm = GUICreate('Test ' & StringReplace(@ScriptName, '.au3', '()'), 160, 199)
    GUISetBkColor(0x000000)
    #forceref $hForm
    Local $idPic = GUICtrlCreatePic('', 0, 0, 160, 199)
    Local $hPic = GUICtrlGetHandle($idPic)

    ; Create bitmap
    Local $hDev = _WinAPI_GetDC($hPic)
    Local $hDC = _WinAPI_CreateCompatibleDC($hDev)
    Local $hSource = _WinAPI_CreateCompatibleBitmapEx($hDev, 160, 199, _WinAPI_SwitchColor(_WinAPI_GetSysColor($COLOR_3DFACE)))
    Local $hSv = _WinAPI_SelectObject($hDC, $hSource)

    ; Draw objects
    Local $tRECT = _WinAPI_CreateRectEx(20, 20, 20, 20)
    Local $hFont = _WinAPI_CreateFont(12, 0, 0, 0, $FW_NORMAL, 0, 0, 0, $DEFAULT_CHARSET, $OUT_DEFAULT_PRECIS, $CLIP_DEFAULT_PRECIS, $DEFAULT_QUALITY, $DEFAULT_PITCH, 'MS Shell Dlg')
    _WinAPI_SetBkMode($hDC, $TRANSPARENT)
    _WinAPI_SelectObject($hDC, $hFont)
    ;Local $hTheme = _WinAPI_OpenThemeData($hForm, 'Button')
    Local $hTheme = _WinAPI_OpenThemeData($hForm, 'Status')
    If Not @error Then
        For $i = 1 To 11
            ;_WinAPI_DrawThemeBackground($hTheme, 3, $i, $hDC, $tRECT)
            _WinAPI_DrawThemeBackground($hTheme, 3, $i, $hDC, $tRECT)
            _WinAPI_OffsetRect($tRECT, 0, 31)
        Next
        _WinAPI_CloseThemeData($hTheme)
    EndIf

    ; Merge bitmap
    Local $hBitmap = _WinAPI_CreateCompatibleBitmap($hDev, 160, 199)
    _WinAPI_SelectObject($hDC, $hBitmap)
    _WinAPI_DrawBitmap($hDC, 0, 0, $hSource, $MERGECOPY)
    _WinAPI_ReleaseDC($hPic, $hDev)
    _WinAPI_SelectObject($hDC, $hSv)
    _WinAPI_DeleteObject($hSource)
    _WinAPI_DeleteDC($hDC)

    ; Set bitmap to control
    _SendMessage($hPic, $STM_SETIMAGE, 0, $hBitmap)
    Local $hObj = _SendMessage($hPic, $STM_GETIMAGE)
    If $hObj <> $hBitmap Then
        _WinAPI_DeleteObject($hBitmap)
    EndIf

    GUISetState(@SW_SHOW)

    Do
    Until GUIGetMsg() = $GUI_EVENT_CLOSE
EndFunc   ;==>_Example

 

Posted

Here are the official GRIPPER theme resources. This would give us an idea of what the width of the actual GRIPPER is for each DPI scale. Then the height would be equal to the width.

For example, on my 125% scaled monitor the GRIPPER is 20x20 pixels.

gripper.7z

Posted (edited)

Here is what I have working so far:

It gets the part size based on DPI as well.

EDIT: Corrected the position of the sizegrip.

 

DllCall("user32.dll", "bool", "SetProcessDpiAwarenessContext", @AutoItX64 ? "int64" : "int", -2)

#include <GDIPlus.au3>
#include <GUIConstantsEx.au3>
#include <GuiStatusBar.au3>
#include <StaticConstants.au3>
#include <WinAPIGdi.au3>
#include <WinAPIRes.au3>
#include <WinAPISysWin.au3>
#include <WinAPITheme.au3>
#include <WindowsConstants.au3>


Opt("MustDeclareVars", 1)

Global Const $SP_GRIPPER = 3
Global $g_hGripSize
Global $g_hGui, $g_hSizebox, $g_hOldProc, $g_hStatus, $g_iHeight, $g_aText, $g_aRatioW, $g_iBkColor, $g_iTextColor, $g_hDots
; Global $g_hBrush ; no need, as _GUICtrlStatusBar_SetBkColor() placed after _WinAPI_SetWindowTheme() does the job correctly

Example()

;==============================================
Func Example()

    _GDIPlus_Startup()

    Local Const $SBS_SIZEBOX = 0x08, $SBS_SIZEGRIP = 0x10
    Local $iW = 300, $iH = 100
    Dim $g_iBkColor = 0x2c2c2c, $g_iTextColor = 0xFFFFFF

    $g_hGui = GUICreate("Resize corner", $iW, $iH, -1, -1, $WS_OVERLAPPEDWINDOW)
    ;GUISetBkColor($g_iBkColor)
    GUISetBkColor(0x000000)

    ;-----------------
    ; Create a sizebox window (Scrollbar class) BEFORE creating the StatusBar control
    $g_hSizebox = _WinAPI_CreateWindowEx(0, "Scrollbar", "", $WS_CHILD + $WS_VISIBLE + $SBS_SIZEBOX, _
        0, 0, 0, 0, $g_hGui) ; $SBS_SIZEBOX or $SBS_SIZEGRIP

    ; Subclass the sizebox (by changing the window procedure associated with the Scrollbar class)
    Local $hProc = DllCallbackRegister('ScrollbarProc', 'lresult', 'hwnd;uint;wparam;lparam')
    $g_hOldProc = _WinAPI_SetWindowLong($g_hSizebox, $GWL_WNDPROC, DllCallbackGetPtr($hProc))

    Local $hCursor = _WinAPI_LoadCursor(0, $OCR_SIZENWSE)
    _WinAPI_SetClassLongEx($g_hSizebox, -12, $hCursor) ; $GCL_HCURSOR = -12

    ; $g_hBrush = _WinAPI_CreateSolidBrush($g_iBkColor)

    ;-----------------
    $g_hStatus = _GUICtrlStatusBar_Create($g_hGui, -1, "", $WS_CLIPSIBLINGS) ; ClipSiblings style +++
    ;Local $aParts[3] = [90, 180, 280]
    Local $aParts[3] = [90, 180, -1]
    If $aParts[Ubound($aParts) - 1] = -1 Then $aParts[Ubound($aParts) - 1] = $iW ; client width size
    _MyGUICtrlStatusBar_SetParts($g_hStatus, $aParts)

    Dim $g_aText[Ubound($aParts)] = ["Part 0", "Part 1", "Part 2"]
    Dim $g_aRatioW[Ubound($aParts)]
    For $i = 0 To UBound($g_aText) - 1
        _GUICtrlStatusBar_SetText($g_hStatus, "", $i, $SBT_OWNERDRAW)
        ;_GUICtrlStatusBar_SetText($g_hStatus, "", $i, $SBT_OWNERDRAW + $SBT_NOBORDERS) ; interesting ?
        $g_aRatioW[$i] = $aParts[$i] / $iW
    Next

    Local $idChangeText = GUICtrlCreateLabel("Change Text", 110, 25, 80, 30, $SS_CENTER + $SS_CENTERIMAGE), $iInc
    GUICtrlSetColor(-1, 0xFFFF00) ; yellow

    ; to allow the setting of StatusBar BkColor at least under Windows 10
    _WinAPI_SetWindowTheme($g_hStatus, "", "")

    ; Set status bar background color
    _GUICtrlStatusBar_SetBkColor($g_hStatus, $g_iBkColor)

    $g_iHeight = _GUICtrlStatusBar_GetHeight($g_hStatus) + 3 ; change the constant (+3) if necessary
    ;$g_hDots = CreateDots($g_iHeight, $g_iHeight, 0xFF000000 + $g_iBkColor, 0xFF000000 + $g_iTextColor)
    Local $hBMP = _WinAPI_ExtractThemeBackground($g_hGUI, 0, 3)
    $g_hDots = _GDIPlus_BitmapCreateFromHBITMAP($hBMP)

    GUIRegisterMsg($WM_SIZE, "WM_SIZE")
    GUIRegisterMsg($WM_MOVE, "WM_MOVE")
    GUIRegisterMsg($WM_DRAWITEM, "WM_DRAWITEM")
    GUISetState()

    While 1
        Switch GUIGetMsg()
            Case $GUI_EVENT_CLOSE
                ExitLoop

            Case $idChangeText
                $iInc += 1
                For $i = 0 To UBound($g_aText) - 1
                    $g_aText[$i] = "Part " & $i & " : Inc " & $iInc
                Next
                _WinAPI_RedrawWindow($g_hStatus)
        EndSwitch
    WEnd

    _GDIPlus_BitmapDispose($g_hDots)
    _GUICtrlStatusBar_Destroy($g_hStatus)
    _WinAPI_DestroyCursor($hCursor)
    ; _WinAPI_DeleteObject($g_hBrush)
    _WinAPI_SetWindowLong($g_hSizebox, $GWL_WNDPROC, $g_hOldProc)
    DllCallbackFree($hProc)
    _GDIPlus_Shutdown()
EndFunc   ;==>Example

;==============================================
Func ScrollbarProc($hWnd, $iMsg, $wParam, $lParam) ; Andreik

    If $iMsg = $WM_PAINT Then
        Local $tPAINTSTRUCT
        Local $hDC = _WinAPI_BeginPaint($hWnd, $tPAINTSTRUCT)
        ;Local $iWidth = DllStructGetData($tPAINTSTRUCT, 'rPaint', 3) - DllStructGetData($tPAINTSTRUCT, 'rPaint', 1)
        ;Local $iHeight = DllStructGetData($tPAINTSTRUCT, 'rPaint', 4) - DllStructGetData($tPAINTSTRUCT, 'rPaint', 2)
        Local $hGraphics = _GDIPlus_GraphicsCreateFromHDC($hDC)
        _GDIPlus_GraphicsDrawImageRect($hGraphics, $g_hDots, 0, 0, $g_hGripSize, $g_hGripSize)
        _GDIPlus_GraphicsDispose($hGraphics)
        _WinAPI_EndPaint($hWnd, $tPAINTSTRUCT)
        Return 0
    EndIf
    Return _WinAPI_CallWindowProc($g_hOldProc, $hWnd, $iMsg, $wParam, $lParam)
EndFunc   ;==>ScrollbarProc

;==============================================
Func CreateDots($iWidth, $iHeight, $iBackgroundColor, $iDotsColor) ; Andreik

    Local $iDotSize = Int($iHeight / 10)
    Local $hBitmap = _GDIPlus_BitmapCreateFromScan0($iWidth, $iHeight)
    Local $hGraphics = _GDIPlus_ImageGetGraphicsContext($hBitmap)
    Local $hBrush = _GDIPlus_BrushCreateSolid($iDotsColor)
    _GDIPlus_GraphicsClear($hGraphics, $iBackgroundColor)
    Local $a[6][2] = [[2,6], [2,4], [2,2], [4,4], [4,2], [6,2]]
    For $i = 0 To UBound($a) - 1
        _GDIPlus_GraphicsFillRect($hGraphics, $iWidth - $iDotSize * $a[$i][0], $iHeight - $iDotSize * $a[$i][1], $iDotSize, $iDotSize, $hBrush)
    Next
    _GDIPlus_BrushDispose($hBrush)
    _GDIPlus_GraphicsDispose($hGraphics)
    Return $hBitmap
EndFunc   ;==>CreateDots

;==============================================
Func _MyGUICtrlStatusBar_SetParts($hWnd, $aPartEdge) ; Pixelsearch

    If Not IsArray($aPartEdge) Then Return False
    Local $iParts = UBound($aPartEdge)
    Local $tParts = DllStructCreate("int[" & $iParts & "]")
    For $i = 0 To $iParts - 1
        DllStructSetData($tParts, 1, $aPartEdge[$i], $i + 1)
    Next
    DllCall("user32.dll", "lresult", "SendMessageW", "hwnd", $hWnd, "uint", $SB_SETPARTS, "wparam", $iParts, "struct*", $tParts)
    _GUICtrlStatusBar_Resize($hWnd)
    Return True
EndFunc   ;==>_MyGUICtrlStatusBar_SetParts

;==============================================
Func WM_SIZE($hWnd, $iMsg, $wParam, $lParam) ; Pixelsearch
    #forceref $iMsg, $wParam, $lParam

    If $hWnd = $g_hGUI Then
        Local Static $bIsSizeBoxShown = True
        Local $aSize = WinGetClientSize($g_hGui)
        Local $aGetParts = _GUICtrlStatusBar_GetParts($g_hStatus)
        Local $aParts[$aGetParts[0]]
        For $i = 0 To $aGetParts[0] - 1
            $aParts[$i] = Int($aSize[0] * $g_aRatioW[$i])
        Next
        If BitAND(WinGetState($g_hGui), $WIN_STATE_MAXIMIZED) Then
            _GUICtrlStatusBar_SetParts($g_hStatus, $aParts) ; set parts until GUI right border (AutoIt function forces it)
            _WinAPI_ShowWindow($g_hSizebox, @SW_HIDE)
            $bIsSizeBoxShown = False
        Else
            If $g_aRatioW[UBound($aParts) -1] <> 1 Then $aParts[UBound($aParts) -1] = $aSize[0] - $g_iHeight ; right size of right part stuck on sizebox (no gap)
            _MyGUICtrlStatusBar_SetParts($g_hStatus, $aParts) ; set parts until sizebox (see preceding line) or until GUI right border
            ;WinMove($g_hSizebox, "", $aSize[0] - $g_iHeight, $aSize[1] - $g_iHeight, $g_iHeight, $g_iHeight)
            WinMove($g_hSizebox, "", $aSize[0] - $g_hGripSize, $aSize[1] - $g_hGripSize, $g_hGripSize, $g_hGripSize)
            If Not $bIsSizeBoxShown Then
                _WinAPI_ShowWindow($g_hSizebox, @SW_SHOW)
                $bIsSizeBoxShown = True
            EndIf
        EndIf
    EndIf
    Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_SIZE

;==============================================
Func WM_MOVE($hWnd, $iMsg, $wParam, $lParam)
    #forceref $iMsg, $wParam, $lParam

    If $hWnd = $g_hGUI Then
        _WinAPI_RedrawWindow($g_hSizebox)
    EndIf
    Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_MOVE

;==============================================
Func WM_DRAWITEM($hWnd, $iMsg, $wParam, $lParam) ; Kafu
    #forceref $hWnd, $iMsg, $wParam

    Local Static $tagDRAWITEM = "uint CtlType;uint CtlID;uint itemID;uint itemAction;uint itemState;hwnd hwndItem;handle hDC;long rcItem[4];ulong_ptr itemData"
    Local $tDRAWITEM = DllStructCreate($tagDRAWITEM, $lParam)
    If $tDRAWITEM.hwndItem <> $g_hStatus Then Return $GUI_RUNDEFMSG ; only process the statusbar

    Local $itemID = $tDRAWITEM.itemID ; status bar part number : 0 if simple bar (or 0, 1, 2... if multi parts)
    Local $hDC = $tDRAWITEM.hDC
    Local $tRect = DllStructCreate("long left;long top;long right;long bottom", DllStructGetPtr($tDRAWITEM, "rcItem"))
    ; _WinAPI_FillRect($hDC, DllStructGetPtr($tRect), $g_hBrush) ; backgound color
    _WinAPI_SetTextColor($hDC, $g_iTextColor) ; text color
    _WinAPI_SetBkMode($hDC, $TRANSPARENT)
    DllStructSetData($tRect, "top", $tRect.top + 1)
    DllStructSetData($tRect, "left", $tRect.left + 1)
    _WinAPI_DrawText($hDC, $g_aText[$itemID], $tRect, $DT_LEFT)

    Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_DRAWITEM

Func _WinAPI_ExtractThemeBackground($hGUI, $iState, $iPart = 3)
    ;Local $hTheme = _WinAPI_OpenThemeData($hGUI, "DarkMode_DarkTheme::Status")   ; Win11 24h2/25H2 only
    Local $hTheme = _WinAPI_OpenThemeData($hGUI, "Status")
    Local $tSIZE = _WinAPI_GetThemePartSize($hTheme, $SP_GRIPPER, 0, Null, Null, $TS_TRUE)
    $g_hGripSize = $tSIZE.X
    If @error Then Return SetError(1, 0, 0)
    Local $hDC = _WinAPI_GetDC($hGUI)
    Local $hHBitmap = _WinAPI_CreateCompatibleBitmap($hDC, $g_hGripSize, $g_hGripSize)
    Local $hMemDC = _WinAPI_CreateCompatibleDC($hDC)
    Local $hObjOld = _WinAPI_SelectObject($hMemDC, $hHBitmap)
    Local $tRECT = _WinAPI_CreateRectEx(0, 0, $g_hGripSize, $g_hGripSize)
    _WinAPI_DrawThemeBackground($hTheme, $iPart, $iState, $hMemDC, $tRECT)
    If @error Then
        _WinAPI_CloseThemeData($hTheme)
        Return SetError(2, 0, 0)
    EndIf
    _WinAPI_SelectObject($hMemDC, $hObjOld)
    _WinAPI_ReleaseDC($hGUI, $hDC)
    _WinAPI_DeleteDC($hMemDC)
    _WinAPI_CloseThemeData($hTheme)
    Return $hHBitmap
EndFunc   ;==>_WinAPI_ExtractThemeBackground

 

Here is an alternative version that applies the DarkMode theme (likely needs Win10 min.) to the statusbar which fills in the color better.

DllCall("user32.dll", "bool", "SetProcessDpiAwarenessContext", @AutoItX64 ? "int64" : "int", -2)

#include <GDIPlus.au3>
#include <GUIConstantsEx.au3>
#include <GuiStatusBar.au3>
#include <StaticConstants.au3>
#include <WinAPIGdi.au3>
#include <WinAPIRes.au3>
#include <WinAPISysWin.au3>
#include <WinAPITheme.au3>
#include <WindowsConstants.au3>


Opt("MustDeclareVars", 1)

Global Const $SP_GRIPPER = 3
Global $g_hGripSize
Global $g_hGui, $g_hSizebox, $g_hOldProc, $g_hStatus, $g_iHeight, $g_aText, $g_aRatioW, $g_iBkColor, $g_iTextColor, $g_hDots
; Global $g_hBrush ; no need, as _GUICtrlStatusBar_SetBkColor() placed after _WinAPI_SetWindowTheme() does the job correctly

Example()

;==============================================
Func Example()

    _GDIPlus_Startup()

    Local Const $SBS_SIZEBOX = 0x08, $SBS_SIZEGRIP = 0x10
    Local $iW = 300, $iH = 100
    Dim $g_iBkColor = 0x2c2c2c, $g_iTextColor = 0xFFFFFF

    $g_hGui = GUICreate("Resize corner", $iW, $iH, -1, -1, $WS_OVERLAPPEDWINDOW)
    ;GUISetBkColor($g_iBkColor)
    GUISetBkColor(0x000000)

    ;-----------------
    ; Create a sizebox window (Scrollbar class) BEFORE creating the StatusBar control
    $g_hSizebox = _WinAPI_CreateWindowEx(0, "Scrollbar", "", $WS_CHILD + $WS_VISIBLE + $SBS_SIZEBOX, _
        0, 0, 0, 0, $g_hGui) ; $SBS_SIZEBOX or $SBS_SIZEGRIP

    ; Subclass the sizebox (by changing the window procedure associated with the Scrollbar class)
    Local $hProc = DllCallbackRegister('ScrollbarProc', 'lresult', 'hwnd;uint;wparam;lparam')
    $g_hOldProc = _WinAPI_SetWindowLong($g_hSizebox, $GWL_WNDPROC, DllCallbackGetPtr($hProc))

    Local $hCursor = _WinAPI_LoadCursor(0, $OCR_SIZENWSE)
    _WinAPI_SetClassLongEx($g_hSizebox, -12, $hCursor) ; $GCL_HCURSOR = -12

    ; $g_hBrush = _WinAPI_CreateSolidBrush($g_iBkColor)

    ;-----------------
    $g_hStatus = _GUICtrlStatusBar_Create($g_hGui, -1, "", $WS_CLIPSIBLINGS) ; ClipSiblings style +++
    ;Local $aParts[3] = [90, 180, 280]
    Local $aParts[3] = [90, 180, -1]
    If $aParts[Ubound($aParts) - 1] = -1 Then $aParts[Ubound($aParts) - 1] = $iW ; client width size
    _MyGUICtrlStatusBar_SetParts($g_hStatus, $aParts)

    Dim $g_aText[Ubound($aParts)] = ["Part 0", "Part 1", "Part 2"]
    Dim $g_aRatioW[Ubound($aParts)]
    For $i = 0 To UBound($g_aText) - 1
        ;_GUICtrlStatusBar_SetText($g_hStatus, "", $i, $SBT_OWNERDRAW)
        _GUICtrlStatusBar_SetText($g_hStatus, "", $i, $SBT_OWNERDRAW + $SBT_NOBORDERS) ; interesting ?
        $g_aRatioW[$i] = $aParts[$i] / $iW
    Next

    Local $idChangeText = GUICtrlCreateLabel("Change Text", 110, 25, 80, 30, $SS_CENTER + $SS_CENTERIMAGE), $iInc
    GUICtrlSetColor(-1, 0xFFFF00) ; yellow

    ; to allow the setting of StatusBar BkColor at least under Windows 10
    ;_WinAPI_SetWindowTheme($g_hStatus, "", "")

    ; Set status bar background color
    ;_GUICtrlStatusBar_SetBkColor($g_hStatus, $g_iBkColor)
    _WinAPI_SetWindowTheme($g_hStatus, 'DarkMode', 'ExplorerStatusBar')

    $g_iHeight = _GUICtrlStatusBar_GetHeight($g_hStatus) + 3 ; change the constant (+3) if necessary
    ;$g_hDots = CreateDots($g_iHeight, $g_iHeight, 0xFF000000 + $g_iBkColor, 0xFF000000 + $g_iTextColor)
    Local $hBMP = _WinAPI_ExtractThemeBackground($g_hGUI, 0, 3)
    $g_hDots = _GDIPlus_BitmapCreateFromHBITMAP($hBMP)

    GUIRegisterMsg($WM_SIZE, "WM_SIZE")
    GUIRegisterMsg($WM_MOVE, "WM_MOVE")
    GUIRegisterMsg($WM_DRAWITEM, "WM_DRAWITEM")
    GUISetState()

    While 1
        Switch GUIGetMsg()
            Case $GUI_EVENT_CLOSE
                ExitLoop

            Case $idChangeText
                $iInc += 1
                For $i = 0 To UBound($g_aText) - 1
                    $g_aText[$i] = "Part " & $i & " : Inc " & $iInc
                Next
                _WinAPI_RedrawWindow($g_hStatus)
        EndSwitch
    WEnd

    _GDIPlus_BitmapDispose($g_hDots)
    _GUICtrlStatusBar_Destroy($g_hStatus)
    _WinAPI_DestroyCursor($hCursor)
    ; _WinAPI_DeleteObject($g_hBrush)
    _WinAPI_SetWindowLong($g_hSizebox, $GWL_WNDPROC, $g_hOldProc)
    DllCallbackFree($hProc)
    _GDIPlus_Shutdown()
EndFunc   ;==>Example

;==============================================
Func ScrollbarProc($hWnd, $iMsg, $wParam, $lParam) ; Andreik

    If $iMsg = $WM_PAINT Then
        Local $tPAINTSTRUCT
        Local $hDC = _WinAPI_BeginPaint($hWnd, $tPAINTSTRUCT)
        ;Local $iWidth = DllStructGetData($tPAINTSTRUCT, 'rPaint', 3) - DllStructGetData($tPAINTSTRUCT, 'rPaint', 1)
        ;Local $iHeight = DllStructGetData($tPAINTSTRUCT, 'rPaint', 4) - DllStructGetData($tPAINTSTRUCT, 'rPaint', 2)
        Local $hGraphics = _GDIPlus_GraphicsCreateFromHDC($hDC)
        _GDIPlus_GraphicsDrawImageRect($hGraphics, $g_hDots, 0, 0, $g_hGripSize, $g_hGripSize)
        _GDIPlus_GraphicsDispose($hGraphics)
        _WinAPI_EndPaint($hWnd, $tPAINTSTRUCT)
        Return 0
    EndIf
    Return _WinAPI_CallWindowProc($g_hOldProc, $hWnd, $iMsg, $wParam, $lParam)
EndFunc   ;==>ScrollbarProc

;==============================================
Func CreateDots($iWidth, $iHeight, $iBackgroundColor, $iDotsColor) ; Andreik

    Local $iDotSize = Int($iHeight / 10)
    Local $hBitmap = _GDIPlus_BitmapCreateFromScan0($iWidth, $iHeight)
    Local $hGraphics = _GDIPlus_ImageGetGraphicsContext($hBitmap)
    Local $hBrush = _GDIPlus_BrushCreateSolid($iDotsColor)
    _GDIPlus_GraphicsClear($hGraphics, $iBackgroundColor)
    Local $a[6][2] = [[2,6], [2,4], [2,2], [4,4], [4,2], [6,2]]
    For $i = 0 To UBound($a) - 1
        _GDIPlus_GraphicsFillRect($hGraphics, $iWidth - $iDotSize * $a[$i][0], $iHeight - $iDotSize * $a[$i][1], $iDotSize, $iDotSize, $hBrush)
    Next
    _GDIPlus_BrushDispose($hBrush)
    _GDIPlus_GraphicsDispose($hGraphics)
    Return $hBitmap
EndFunc   ;==>CreateDots

;==============================================
Func _MyGUICtrlStatusBar_SetParts($hWnd, $aPartEdge) ; Pixelsearch

    If Not IsArray($aPartEdge) Then Return False
    Local $iParts = UBound($aPartEdge)
    Local $tParts = DllStructCreate("int[" & $iParts & "]")
    For $i = 0 To $iParts - 1
        DllStructSetData($tParts, 1, $aPartEdge[$i], $i + 1)
    Next
    DllCall("user32.dll", "lresult", "SendMessageW", "hwnd", $hWnd, "uint", $SB_SETPARTS, "wparam", $iParts, "struct*", $tParts)
    _GUICtrlStatusBar_Resize($hWnd)
    Return True
EndFunc   ;==>_MyGUICtrlStatusBar_SetParts

;==============================================
Func WM_SIZE($hWnd, $iMsg, $wParam, $lParam) ; Pixelsearch
    #forceref $iMsg, $wParam, $lParam

    If $hWnd = $g_hGUI Then
        Local Static $bIsSizeBoxShown = True
        Local $aSize = WinGetClientSize($g_hGui)
        Local $aGetParts = _GUICtrlStatusBar_GetParts($g_hStatus)
        Local $aParts[$aGetParts[0]]
        For $i = 0 To $aGetParts[0] - 1
            $aParts[$i] = Int($aSize[0] * $g_aRatioW[$i])
        Next
        If BitAND(WinGetState($g_hGui), $WIN_STATE_MAXIMIZED) Then
            _GUICtrlStatusBar_SetParts($g_hStatus, $aParts) ; set parts until GUI right border (AutoIt function forces it)
            _WinAPI_ShowWindow($g_hSizebox, @SW_HIDE)
            $bIsSizeBoxShown = False
        Else
            If $g_aRatioW[UBound($aParts) -1] <> 1 Then $aParts[UBound($aParts) -1] = $aSize[0] - $g_iHeight ; right size of right part stuck on sizebox (no gap)
            _MyGUICtrlStatusBar_SetParts($g_hStatus, $aParts) ; set parts until sizebox (see preceding line) or until GUI right border
            ;WinMove($g_hSizebox, "", $aSize[0] - $g_iHeight, $aSize[1] - $g_iHeight, $g_iHeight, $g_iHeight)
            WinMove($g_hSizebox, "", $aSize[0] - $g_hGripSize, $aSize[1] - $g_hGripSize, $g_hGripSize, $g_hGripSize)
            If Not $bIsSizeBoxShown Then
                _WinAPI_ShowWindow($g_hSizebox, @SW_SHOW)
                $bIsSizeBoxShown = True
            EndIf
        EndIf
    EndIf
    Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_SIZE

;==============================================
Func WM_MOVE($hWnd, $iMsg, $wParam, $lParam)
    #forceref $iMsg, $wParam, $lParam

    If $hWnd = $g_hGUI Then
        _WinAPI_RedrawWindow($g_hSizebox)
    EndIf
    Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_MOVE

;==============================================
Func WM_DRAWITEM($hWnd, $iMsg, $wParam, $lParam) ; Kafu
    #forceref $hWnd, $iMsg, $wParam

    Local Static $tagDRAWITEM = "uint CtlType;uint CtlID;uint itemID;uint itemAction;uint itemState;hwnd hwndItem;handle hDC;long rcItem[4];ulong_ptr itemData"
    Local $tDRAWITEM = DllStructCreate($tagDRAWITEM, $lParam)
    If $tDRAWITEM.hwndItem <> $g_hStatus Then Return $GUI_RUNDEFMSG ; only process the statusbar

    Local $itemID = $tDRAWITEM.itemID ; status bar part number : 0 if simple bar (or 0, 1, 2... if multi parts)
    Local $hDC = $tDRAWITEM.hDC
    Local $tRect = DllStructCreate("long left;long top;long right;long bottom", DllStructGetPtr($tDRAWITEM, "rcItem"))
    ; _WinAPI_FillRect($hDC, DllStructGetPtr($tRect), $g_hBrush) ; backgound color
    _WinAPI_SetTextColor($hDC, $g_iTextColor) ; text color
    _WinAPI_SetBkMode($hDC, $TRANSPARENT)
    DllStructSetData($tRect, "top", $tRect.top + 1)
    DllStructSetData($tRect, "left", $tRect.left + 1)
    _WinAPI_DrawText($hDC, $g_aText[$itemID], $tRect, $DT_LEFT)

    Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_DRAWITEM

Func _WinAPI_ExtractThemeBackground($hGUI, $iState, $iPart = 3)
    ;Local $hTheme = _WinAPI_OpenThemeData($hGUI, "DarkMode_DarkTheme::Status")   ; Win11 24h2/25H2 only
    Local $hTheme = _WinAPI_OpenThemeData($hGUI, "Status")
    Local $tSIZE = _WinAPI_GetThemePartSize($hTheme, $SP_GRIPPER, 0, Null, Null, $TS_TRUE)
    $g_hGripSize = $tSIZE.X
    If @error Then Return SetError(1, 0, 0)
    Local $hDC = _WinAPI_GetDC($hGUI)
    Local $hHBitmap = _WinAPI_CreateCompatibleBitmap($hDC, $g_hGripSize, $g_hGripSize)
    Local $hMemDC = _WinAPI_CreateCompatibleDC($hDC)
    Local $hObjOld = _WinAPI_SelectObject($hMemDC, $hHBitmap)
    Local $tRECT = _WinAPI_CreateRectEx(0, 0, $g_hGripSize, $g_hGripSize)
    _WinAPI_DrawThemeBackground($hTheme, $iPart, $iState, $hMemDC, $tRECT)
    If @error Then
        _WinAPI_CloseThemeData($hTheme)
        Return SetError(2, 0, 0)
    EndIf
    _WinAPI_SelectObject($hMemDC, $hObjOld)
    _WinAPI_ReleaseDC($hGUI, $hDC)
    _WinAPI_DeleteDC($hMemDC)
    _WinAPI_CloseThemeData($hTheme)
    Return $hHBitmap
EndFunc   ;==>_WinAPI_ExtractThemeBackground

 

Edited by WildByDesign
Posted (edited)

My two examples above both work quite well, but there are two problems to work out.

  1. In the first example with no theme set, there is white space showing around the sizegrip. This is because I had to resize the sizebox (scrollbar) window to match the DPI-sized sizegrip resource. That was the only way that I could keep it sharp with DPI. The second example that has theme applied shows a black border around the sizegrip. In either case, somehow we need to paint over that area again. I'm not sure if we can add another layer of painting in ScrollbarProc to cover the initial size of the sizegrip area, with the DPI-sized sizegrip resource on top. I don't know how to do this yet.
  2. The sizegrip resource is supposed to be a transparent image. Yet the first example shows with a black background. And if I use the Win11 24H2/25H2 DarkMode_DarkTheme::Status resource, it shows with a grey background. I assume that DrawThemeBackground paints the transparent dots plus whatever else is involved in the theming engine. We could consider setting the sizegrip (Scrollbar) window as a layered window with WS_EX_LAYERED and setting the attribute to make the black background transparent. I tried this and it does work. The only problem is that it exposes more of the white layer underneath from problem 1.

Anyway, this is an interesting experiment so far.

EDIT: I am getting somewhat better results after bringing back the $g_hBrush and RectFill that were initially commented out.

Win10/Win11:

statusbar.png

Win11 24H2/25H2 only:

statusbar2.png

Edited by WildByDesign
Posted (edited)

It took me 4 days because I'm such a rookie. But I finally got it. This example does set the dark mode theme to the statusbar and therefore does not use ownerdraw. In my opinion, I think this looks nicer overall. But that is just my opinion. The sizegrip is completely DPI aware. :)

status.png

EDIT: Part of the border is being cut off so I will have to modify the size slightly.

EDIT2: Here is Win11 24H2/25H2 DarkMode_DarkTheme::Status themed statusbar:

status.png

DllCall("user32.dll", "bool", "SetProcessDpiAwarenessContext", @AutoItX64 ? "int64" : "int", -2)

#include <GDIPlus.au3>
#include <GUIConstantsEx.au3>
#include <GuiStatusBar.au3>
#include <StaticConstants.au3>
#include <WinAPIGdi.au3>
#include <WinAPIRes.au3>
#include <WinAPISysWin.au3>
#include <WinAPITheme.au3>
#include <WindowsConstants.au3>

Opt("MustDeclareVars", 1)

Global $g_hGui, $g_hSizebox, $g_hOldProc, $g_hStatus, $g_iHeight, $g_aText, $g_aRatioW, $g_iBkColor, $g_iTextColor, $g_hDots
Global Const $SP_GRIPPER = 3

Example()

;==============================================
Func Example()

    _GDIPlus_Startup()

    Local Const $SBS_SIZEBOX = 0x08, $SBS_SIZEGRIP = 0x10
    Local $iW = 300, $iH = 100
    Dim $g_iBkColor = 0x1c1c1c, $g_iTextColor = 0xFFFFFF

    $g_hGui = GUICreate("Resize corner", $iW, $iH, -1, -1, $WS_OVERLAPPEDWINDOW)
    GUISetBkColor(0x303030)

    ;-----------------
    ; Create a sizebox window (Scrollbar class) BEFORE creating the StatusBar control
    $g_hSizebox = _WinAPI_CreateWindowEx(0, "Scrollbar", "", $WS_CHILD + $WS_VISIBLE + $SBS_SIZEBOX, _
        0, 0, 0, 0, $g_hGui) ; $SBS_SIZEBOX or $SBS_SIZEGRIP

    ; Subclass the sizebox (by changing the window procedure associated with the Scrollbar class)
    Local $hProc = DllCallbackRegister('ScrollbarProc', 'lresult', 'hwnd;uint;wparam;lparam')
    $g_hOldProc = _WinAPI_SetWindowLong($g_hSizebox, $GWL_WNDPROC, DllCallbackGetPtr($hProc))

    Local $hCursor = _WinAPI_LoadCursor(0, $OCR_SIZENWSE)
    _WinAPI_SetClassLongEx($g_hSizebox, -12, $hCursor) ; $GCL_HCURSOR = -12

    ;-----------------
    $g_hStatus = _GUICtrlStatusBar_Create($g_hGui, -1, "", $WS_CLIPSIBLINGS) ; ClipSiblings style +++
    Local $aParts[3] = [90, 180, -1]
    If $aParts[Ubound($aParts) - 1] = -1 Then $aParts[Ubound($aParts) - 1] = $iW ; client width size
    _GUICtrlStatusBar_SetParts($g_hStatus, $aParts)

    Dim $g_aText[Ubound($aParts)] = ["Part 0", "Part 1", "Part 2"]
    Dim $g_aRatioW[Ubound($aParts)]
    For $i = 0 To UBound($g_aText) - 1
        _GUICtrlStatusBar_SetText($g_hStatus, $g_aText[$i], $i)
        ; _GUICtrlStatusBar_SetText($g_hStatus, "", $i, $SBT_OWNERDRAW + $SBT_NOBORDERS) ; interesting ?
        $g_aRatioW[$i] = $aParts[$i] / $iW
    Next

    Local $idChangeText = GUICtrlCreateLabel("Change Text", 110, 25, 80, 30, $SS_CENTER + $SS_CENTERIMAGE), $iInc
    GUICtrlSetColor(-1, 0xFFFF00) ; yellow

    $g_iHeight = WinGetPos($g_hStatus)[3] - 3
    $g_hDots = CreateDots($g_iHeight, $g_iHeight, 0xFF000000 + $g_iBkColor, 0xFF000000 + $g_iTextColor)

    GUIRegisterMsg($WM_SIZE, "WM_SIZE")
    GUIRegisterMsg($WM_WINDOWPOSCHANGED, "WM_WINDOWPOSCHANGED")

    _WinAPI_SetWindowTheme($g_hStatus, 'DarkMode', 'ExplorerStatusBar') ; 0x1c1c1c background
    ;_WinAPI_SetWindowTheme($g_hStatus, 'DarkMode_DarkTheme', 'Status') ; 0x3b3b3b background (Win11 24H2/25H2 only)

    GUISetState()

    While 1
        Switch GUIGetMsg()
            Case $GUI_EVENT_CLOSE
                ExitLoop

            Case $idChangeText
                $iInc += 1
                For $i = 0 To UBound($g_aText) - 1
                    ;$g_aText[$i] = "Part " & $i & " : Inc " & $iInc
                    _GUICtrlStatusBar_SetText($g_hStatus, $g_aText[$i] & " : Inc " & $iInc , $i)
                Next
                _WinAPI_RedrawWindow($g_hStatus)
        EndSwitch
    WEnd

    _GDIPlus_BitmapDispose($g_hDots)
    _GUICtrlStatusBar_Destroy($g_hStatus)
    _WinAPI_DestroyCursor($hCursor)
    _WinAPI_SetWindowLong($g_hSizebox, $GWL_WNDPROC, $g_hOldProc)
    DllCallbackFree($hProc)
    _GDIPlus_Shutdown()
EndFunc   ;==>Example

;==============================================
Func ScrollbarProc($hWnd, $iMsg, $wParam, $lParam) ; Andreik

    If $iMsg = $WM_PAINT Then
        Local $tPAINTSTRUCT
        Local $hDC = _WinAPI_BeginPaint($hWnd, $tPAINTSTRUCT)
        Local $iWidth = DllStructGetData($tPAINTSTRUCT, 'rPaint', 3) - DllStructGetData($tPAINTSTRUCT, 'rPaint', 1)
        Local $iHeight = DllStructGetData($tPAINTSTRUCT, 'rPaint', 4) - DllStructGetData($tPAINTSTRUCT, 'rPaint', 2)
        Local $hGraphics = _GDIPlus_GraphicsCreateFromHDC($hDC)
        _GDIPlus_GraphicsDrawImageRect($hGraphics, $g_hDots, 0, 0, $iWidth, $iHeight)
        _GDIPlus_GraphicsDispose($hGraphics)

        Local $hTheme = _WinAPI_OpenThemeData($g_hGui, 'Status')
        Local $tSIZE = _WinAPI_GetThemePartSize($hTheme, $SP_GRIPPER, 0, Null, Null, $TS_TRUE)
        Local $g_hGripSize = $tSIZE.X
        Local $tRECT = _WinAPI_CreateRectEx($g_iHeight - $g_hGripSize, $g_iHeight - $g_hGripSize, $g_hGripSize, $g_hGripSize)
        _WinAPI_SetBkMode($hDC, $TRANSPARENT)
        _WinAPI_DrawThemeBackground($hTheme, 3, 0, $hDC, $tRECT)
        _WinAPI_CloseThemeData($hTheme)

        _WinAPI_EndPaint($hWnd, $tPAINTSTRUCT)
        Return 0
    EndIf
    Return _WinAPI_CallWindowProc($g_hOldProc, $hWnd, $iMsg, $wParam, $lParam)
EndFunc   ;==>ScrollbarProc

;==============================================
Func CreateDots($iWidth, $iHeight, $iBackgroundColor, $iDotsColor) ; Andreik

    Local $hBitmap = _GDIPlus_BitmapCreateFromScan0($iWidth, $iHeight)
    Local $hGraphics = _GDIPlus_ImageGetGraphicsContext($hBitmap)
    Local $hBrush = _GDIPlus_BrushCreateSolid($iDotsColor)
    _GDIPlus_GraphicsClear($hGraphics, $iBackgroundColor)
    _GDIPlus_BrushDispose($hBrush)
    _GDIPlus_GraphicsDispose($hGraphics)
    Return $hBitmap
EndFunc   ;==>CreateDots

;==============================================
Func WM_SIZE($hWnd, $iMsg, $wParam, $lParam) ; Pixelsearch
    #forceref $iMsg, $wParam, $lParam

    If $hWnd = $g_hGUI Then
        Local Static $bIsSizeBoxShown = True
        Local $aSize = WinGetClientSize($g_hGui)
        Local $aGetParts = _GUICtrlStatusBar_GetParts($g_hStatus)
        Local $aParts[$aGetParts[0]]
        For $i = 0 To $aGetParts[0] - 1
            $aParts[$i] = Int($aSize[0] * $g_aRatioW[$i])
        Next
        If BitAND(WinGetState($g_hGui), $WIN_STATE_MAXIMIZED) Then
            _GUICtrlStatusBar_SetParts($g_hStatus, $aParts) ; set parts until GUI right border (AutoIt function forces it)
            _WinAPI_ShowWindow($g_hSizebox, @SW_HIDE)
            $bIsSizeBoxShown = False
        Else
            If $g_aRatioW[UBound($aParts) -1] <> 1 Then $aParts[UBound($aParts) -1] = $aSize[0] - $g_iHeight ; right size of right part stuck on sizebox (no gap)
            _GUICtrlStatusBar_SetParts($g_hStatus, $aParts) ; set parts until sizebox (see preceding line) or until GUI right border
            WinMove($g_hSizebox, "", $aSize[0] - $g_iHeight, $aSize[1] - $g_iHeight, $g_iHeight, $g_iHeight)
            If Not $bIsSizeBoxShown Then
                _WinAPI_ShowWindow($g_hSizebox, @SW_SHOW)
                $bIsSizeBoxShown = True
            EndIf
        EndIf
    EndIf
    Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_SIZE

;==============================================
Func WM_WINDOWPOSCHANGED($hWnd, $iMsg, $wParam, $lParam)
    #forceref $iMsg, $wParam, $lParam

    If $hWnd = $g_hGUI Then
        _WinAPI_RedrawWindow($g_hSizebox)
    EndIf
    Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_WINDOWPOSCHANGED

 

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