WildByDesign Posted March 10 Posted March 10 This is essentially a continuation of the Resizable status bar without SBARS_SIZEGRIP topic in which the wonderful @pixelsearch figured out a solution for doing an OWNERDRAW of the dark mode statusbar parts. The sizegrip dots are drawn using GDI+ in that example. I have since figured out a method using _WinAPI_DrawThemeBackground to paint the SP_GRIPPER part and _WinAPI_GetThemePartSize to ensure proper size with high DPI support. My overall goal is to add statusbar support to the GUIDarkTheme UDF. The problem that I am facing is that the method used in the example from that thread creates a separate window (Scrollbar class) to paint the dots on. And while that works beautifully in the example, it becomes much more complex adding it to the UDF. The Scrollbar window constantly loses focus and disappears in examples that have more controls such as the SampleControls GUI example. Since Notepad++ has some of the absolute best dark mode subclassing techniques, I thought to look there. First of all, I noticed that Notepad++ does not use a separate window to paint the SP_GRIPPER part. They seem to paint it directly on the statusbar which would likely solve my issues with the Scrollbar window disappearing. All of the subclassing code for Notepad++ statusbar is contained in StatusBar.cpp. One thing that I found interesting is that they use ODA_DRAWENTIRE which we don't seem to have a Const variable for in AutoIt. They make use of WM_ERASEBKGND, WM_PAINT and WM_PRINTCLIENT. The majority of the drawing seems to take place in WM_PRINTCLIENT. They seem to paint the individual parts the same way as @pixelsearch does in his example. However, the part that I don't understand at all is how they paint the SP_GRIPPER to the bottom right corner of the statusbar. I will share an example of where I left off. It has the code for obtaining, measuring and painting the SP_GRIPPER in the ScrollbarProc function because that is the only thing that I could figure out. But ideally, I would like to get rid of the Scrollbar window and paint directly on the statusbar as Notepad++ does. If there is somebody that has the subclassing understanding and is willing to help with this, I would really appreciate it. As always, I appreciate everyone's time and efforts. Thank you. expandcollapse popupDllCall("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) ; _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") GUIRegisterMsg($WM_DRAWITEM, "WM_DRAWITEM") _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) ; paint SP_GRIPPER 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 ;============================================== 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
WildByDesign Posted March 11 Author Posted March 11 I have something that works pretty decent so far. If anyone wants to help improve it, please feel free. Dragging the GUI is covered with WM_WINDOWPOSCHANGED and work beautifully. The most significant issue is that WM_SIZE wont draw it until after the move is complete. So if anyone can help with this part, that would be the issue that needs the most help. expandcollapse popup; DPI scaling DllCall("user32.dll", "bool", "SetProcessDpiAwarenessContext", @AutoItX64 ? "int64" : "int", -2) #include <WindowsStylesConstants.au3> #include <GUIConstantsEx.au3> #include <GuiStatusBar.au3> #include <WindowsNotifsConstants.au3> #include <WinAPITheme.au3> #include <WinAPIGdiDC.au3> #include <WinAPIGdi.au3> Global $g_hStatus, $g_hGui Global $g_hBrush Example() Func Example() ; Create GUI $g_hGui = GUICreate("StatusBar Resize (v" & @AutoItVersion & ")", 450, 320, 100, 100, $WS_OVERLAPPEDWINDOW) GUISetBkColor(0x202020) ; Set parts Local $hStatus = _GUICtrlStatusBar_Create($g_hGui) $g_hStatus = $hStatus Local $aParts[3] = [75, 150, -1] _GUICtrlStatusBar_SetParts($hStatus, $aParts) _GUICtrlStatusBar_SetText($hStatus, "Part 0") _GUICtrlStatusBar_SetText($hStatus, "Part 1", 1) _GUICtrlStatusBar_SetText($hStatus, "Part 2", 2) _WinAPI_SetWindowTheme($g_hStatus, 'DarkMode', 'ExplorerStatusBar') ; 0x1c1c1c background ;_WinAPI_SetWindowTheme($g_hStatus, 'DarkMode_DarkTheme', 'Status') ; 0x3b3b3b background (Win11 24H2/25H2 only) GUISetState(@SW_SHOW) _DrawStatusGrip() GUIRegisterMsg($WM_SIZE, "WM_SIZE") GUIRegisterMsg($WM_WINDOWPOSCHANGED, "_WM_WINDOWPOSCHANGED") ; Loop until the user exits. Do Until GUIGetMsg() = $GUI_EVENT_CLOSE GUIDelete() EndFunc ;==>Example ; Resize the status bar when GUI size changes Func WM_SIZE($hWnd, $iMsg, $wParam, $lParam) #forceref $hWnd, $iMsg, $wParam, $lParam _GUICtrlStatusBar_Resize($g_hStatus) _DrawStatusGrip() ; does not seem to catch it AdlibRegister("_DrawStatusGrip", 10) ; seems to be only way so far Return $GUI_RUNDEFMSG EndFunc ;==>WM_SIZE Func _WM_WINDOWPOSCHANGED($hWnd, $iMsg, $wParam, $lParam) #forceref $iMsg, $wParam, $lParam If $hWnd <> $g_hGui Then Return $GUI_RUNDEFMSG _DrawStatusGrip() Return $GUI_RUNDEFMSG EndFunc ;==>_WM_WINDOWPOSCHANGED Func _DrawStatusGrip() If BitAND(WinGetState($g_hGui), $WIN_STATE_MAXIMIZED) Then Return Local Const $SP_GRIPPER = 3 Local $hDC = _WinAPI_GetDC($g_hGui) ; obtain SP_GRIPPER part and size 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 $aClientSize = WinGetClientSize($g_hGui) ; need to fill first to cover borders $g_hBrush = _WinAPI_CreateSolidBrush(0x1c1c1c) Local $tRECT1 = _WinAPI_CreateRectEx($aClientSize[0] - $g_hGripSize - 2, $aClientSize[1] - $g_hGripSize - 2, $g_hGripSize + 2, $g_hGripSize + 2) _WinAPI_FillRect($hDC, DllStructGetPtr($tRECT1), $g_hBrush) ; draw SP_GRIPPER part Local $tRECT2 = _WinAPI_CreateRectEx($aClientSize[0] - $g_hGripSize, $aClientSize[1] - $g_hGripSize, $g_hGripSize, $g_hGripSize) _WinAPI_DrawThemeBackground($hTheme, 3, 0, $hDC, $tRECT2) _WinAPI_CloseThemeData($hTheme) _WinAPI_ReleaseDC($g_hGui, $hDC) _WinAPI_DeleteObject($g_hBrush) AdlibUnRegister("_DrawStatusGrip") EndFunc
pixelsearch Posted March 11 Posted March 11 If _DrawStatusGrip() doesn't display anymore the gripper when called from functions WM_SIZE / WM_MOVE / WM_WINDOWPOSCHANGED, why not trying it from function WM_EXITSIZEMOVE ? It seems to work and the gripper reappears correctly when the GUI size/move has ended. Here are the changes I did in your last script : * No Adlib * No _DrawStatusGrip() from Func WM_SIZE * Func _WM_WINDOWPOSCHANGED becomes Func WM_EXITSIZEMOVE * GUIRegisterMsg($WM_EXITSIZEMOVE, "WM_EXITSIZEMOVE") Hope it helps WildByDesign 1 "I think you are searching a bug where there is no bug... don't listen to bad advice."
WildByDesign Posted March 11 Author Posted March 11 19 minutes ago, pixelsearch said: If _DrawStatusGrip() doesn't display anymore the gripper when called from functions WM_SIZE / WM_MOVE / WM_WINDOWPOSCHANGED, why not trying it from function WM_EXITSIZEMOVE ? Thanks. This works quite well and it is nice to get rid of the Adlib. 21 minutes ago, pixelsearch said: * Func _WM_WINDOWPOSCHANGED becomes Func WM_EXITSIZEMOVE I don't think that I can get rid of WM_WINDOWPOSCHANGED though because WM_EXITSIZEMOVE does not work when restoring the window from a maximized state. So I would probably have to keep both of them. I wish that I could figure out how to get the grip to draw on the statusbar during sizing as well. But I am assuming that it would require subclassing the wm_paint for the statusbar. That is too far above my knowledge right now. pixelsearch 1
pixelsearch Posted March 11 Posted March 11 Just now, WildByDesign said: I don't think that I can get rid of WM_WINDOWPOSCHANGED though because WM_EXITSIZEMOVE does not work when restoring the window from a maximized state. So I would probably have to keep both of them. The never ending problem after minimizing / maximizing / restoring WM_WINDOWPOSCHANGED doesn't solve this on my computer and the gripper doesn't reappear after restoring. Also WM_WINDOWPOSCHANGED is called dozen of times while resizing, it would be great to avoid it. What follows seems to do it, restoring after maximiming (or after minimizing) makes the gripper reappear : While True Switch GUIGetMsg() Case $GUI_EVENT_CLOSE ExitLoop Case $GUI_EVENT_RESTORE _DrawStatusGrip() EndSwitch WEnd WildByDesign 1 "I think you are searching a bug where there is no bug... don't listen to bad advice."
WildByDesign Posted March 11 Author Posted March 11 17 minutes ago, pixelsearch said: What follows seems to do it, restoring after maximiming (or after minimizing) makes the gripper reappear : This works very well, thanks. This suggestion as well as your suggestion to use WM_EXITSIZEMOVE instead of WM_WINDOWPOSCHANGED have both been great suggestions. Plus getting rid of the adlib, of course.
WildByDesign Posted March 11 Author Posted March 11 This current idea of mine is more flawed than I had expected. Since my goal is to create something that can be added on (UDF) to any existing AutoIt GUI script that contains a statusbar. I just realized that this method does not work at all with WS_EX_COMPOSITED and I use that in a few of my GUI projects.
pixelsearch Posted March 12 Posted March 12 12 hours ago, WildByDesign said: I just realized that this method does not work at all with WS_EX_COMPOSITED If not mistaken, it doesn't work if you apply that style at GUI creation. Why not trying to apply the style only during the size/move phase, with the following code ? It works on my computer and the status bar doesn't flicker anymore during the size/move phase #include <WinAPISysWin.au3> ... GUIRegisterMsg($WM_ENTERSIZEMOVE, "WM_ENTERSIZEMOVE") GUIRegisterMsg($WM_EXITSIZEMOVE, "WM_EXITSIZEMOVE") GUIRegisterMsg($WM_SIZE, "WM_SIZE") ... Func WM_ENTERSIZEMOVE($hWnd, $iMsg, $wParam, $lParam) #forceref $iMsg, $wParam, $lParam Switch $hWnd Case $g_hGui _WinAPI_SetWindowLong($g_hGui, $GWL_EXSTYLE, BitOR(_WinAPI_GetWindowLong($g_hGui, $GWL_EXSTYLE), $WS_EX_COMPOSITED)) EndSwitch Return $GUI_RUNDEFMSG EndFunc ;==>WM_ENTERSIZEMOVE Func WM_EXITSIZEMOVE($hWnd, $iMsg, $wParam, $lParam) #forceref $iMsg, $wParam, $lParam Switch $hWnd Case $g_hGui _WinAPI_SetWindowLong($g_hGui, $GWL_EXSTYLE, BitXOR(_WinAPI_GetWindowLong($g_hGui, $GWL_EXSTYLE), $WS_EX_COMPOSITED)) _DrawStatusGrip() EndSwitch Return $GUI_RUNDEFMSG EndFunc ;==>WM_EXITSIZEMOVE Func WM_SIZE($hWnd, $iMsg, $wParam, $lParam) #forceref $iMsg, $wParam, $lParam Switch $hWnd Case $g_hGui _GUICtrlStatusBar_Resize($g_hStatus) EndSwitch Return $GUI_RUNDEFMSG EndFunc ;==>WM_SIZE WildByDesign 1 "I think you are searching a bug where there is no bug... don't listen to bad advice."
Solution WildByDesign Posted March 12 Author Solution Posted March 12 3 hours ago, pixelsearch said: Why not trying to apply the style only during the size/move phase, with the following code ? This works quite well for the purpose of us testing it. But overall, I'm not sure my current idea is best for the perspective of a UDF. Someone might have a GUI that relies on WS_EX_COMPOSITED, so I don't want to make changes that can cause problems. With that being said, I think that your original script which uses a Scrollbar window to paint the dots on is likely the best option. It is very versatile and works in way more scenarios. I tried that initially but ran into problems. The problems that I had related to the following comment from your script: ; Create a sizebox window (Scrollbar class) BEFORE creating the StatusBar control You put that comment there with very good reason. That is what would determine Z-order and is very crucial for how your script works. From the perspective, the statusbar would already be created. At some point, I tried collecting status details, destroy statusbar and then create sizebox and statusbar. I found a way to fix this. So now, I collect status details, create sizebox and change Z-order with the following: _WinAPI_SetWindowPos($g_hSizebox, $HWND_TOP, $aPos[0], $aPos[1], $aPos[2], $aPos[3], 0) This method seems to work very well. I will share the script from where I left off. It isn't complete yet. I have to collect the details of the statusbar and do the math/measurements for the ratio (for resizing parts) after creation because in this case we are (in theory) working on other GUIs. I still have to clean up a bit more before adding to GUIDarkTheme UDF. More testing as well. But so far, so good. I had to change some measurements to not cut off the statusbar borders as well. expandcollapse popupDllCall("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> #include <Array.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 Global $hTheme = _WinAPI_OpenThemeData($g_hGui, 'Status') Global $tSIZE = _WinAPI_GetThemePartSize($hTheme, $SP_GRIPPER, 0, Null, Null, $TS_TRUE) Global $g_hGripSize = $tSIZE.X Global $hStatusProc = DllCallbackRegister('__GUIDarkMode_StatusProc', 'ptr', 'hwnd;uint;wparam;lparam') Global $hPrevProc, $hCursor, $hSizeboxProc OnAutoItExitRegister("_ExitStatus") Func _ExitStatus() _WinAPI_CloseThemeData($hTheme) _WinAPI_SetWindowLong($g_hGui, -4, $hPrevProc) DllCallbackFree($hStatusProc) _GDIPlus_BitmapDispose($g_hDots) _GUICtrlStatusBar_Destroy($g_hStatus) _WinAPI_DestroyCursor($hCursor) _WinAPI_SetWindowLong($g_hSizebox, $GWL_WNDPROC, $g_hOldProc) DllCallbackFree($hSizeboxProc) _GDIPlus_Shutdown() EndFunc Example() Func Example() _GDIPlus_Startup() Local $iW = 300, $iH = 100 ;Dim $g_iBkColor = 0x1c1c1c, $g_iTextColor = 0xFFFFFF Dim $g_iBkColor = 0x1c1c1c, $g_iTextColor = 0xFFFFFF $g_hGui = GUICreate("Resize corner", $iW, $iH, -1, -1, $WS_OVERLAPPEDWINDOW) GUISetBkColor(0x303030) $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, $g_aText[$i], $i, $SBT_NOBORDERS) Next Local $idChangeText = GUICtrlCreateLabel("Change Text", 110, 25, 80, 30, $SS_CENTER + $SS_CENTERIMAGE), $iInc GUICtrlSetColor(-1, 0xFFFF00) ; yellow __GUIDarkMode_StatusRatio() __GUIDarkMode_CreateSizebox() _WinAPI_SetWindowTheme($g_hStatus, 'DarkMode', 'ExplorerStatusBar') ; 0x1c1c1c background ;_WinAPI_SetWindowTheme($g_hStatus, 'DarkMode_DarkTheme', 'Status') ; 0x3b3b3b background (Win11 24H2/25H2 only) $hPrevProc = _WinAPI_SetWindowLong($g_hGui, -4, DllCallbackGetPtr($hStatusProc)) GUISetState() While 1 Switch GUIGetMsg() Case $GUI_EVENT_CLOSE Exit 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 EndFunc ;==>Example Func __GUIDarkMode_SizeboxProc($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_GraphicsDrawImageRect($hGraphics, $g_hDots, 0, 0, $g_hGripSize + 2, $g_hGripSize + 2) _GDIPlus_GraphicsDispose($hGraphics) ; paint sizegrip ;Local $tRECT = _WinAPI_CreateRectEx($g_iHeight - $g_hGripSize, $g_iHeight - $g_hGripSize, $g_hGripSize, $g_hGripSize) Local $tRECT = _WinAPI_CreateRectEx($g_hGripSize + 2 - $g_hGripSize + 1, $g_hGripSize + 2 - $g_hGripSize + 1, $g_hGripSize, $g_hGripSize) _WinAPI_DrawThemeBackground($hTheme, 3, 0, $hDC, $tRECT) _WinAPI_EndPaint($hWnd, $tPAINTSTRUCT) Return 0 EndIf Return _WinAPI_CallWindowProc($g_hOldProc, $hWnd, $iMsg, $wParam, $lParam) EndFunc ;==>__GUIDarkMode_SizeboxProc 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 _WinAPI_RedrawWindow($g_hSizebox) 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) WinMove($g_hSizebox, "", $aSize[0] - $g_hGripSize - 2 - 1, $aSize[1] - $g_hGripSize - 2 - 1, $g_hGripSize + 2, $g_hGripSize + 2) If Not $bIsSizeBoxShown Then _WinAPI_ShowWindow($g_hSizebox, @SW_SHOW) $bIsSizeBoxShown = True EndIf _WinAPI_RedrawWindow($g_hSizebox) 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 Func __GUIDarkMode_StatusProc($hWnd, $iMsg, $wParam, $lParam) Local $sContinue = $GUI_RUNDEFMSG Switch $iMsg Case $WM_SIZE $sContinue = _WM_SIZE($hWnd, $iMsg, $wParam, $lParam) Case $WM_WINDOWPOSCHANGED $sContinue = _WM_WINDOWPOSCHANGED($hWnd, $iMsg, $wParam, $lParam) EndSwitch If $sContinue = $GUI_RUNDEFMSG Then Return _WinAPI_CallWindowProc($hPrevProc, $hWnd, $iMsg, $wParam, $lParam) EndFunc ;==>__GUIDarkMode_StatusProc Func __GUIDarkMode_StatusRatio() ; calculate ratio need for the resizing of statusbar parts Local $iGuiWidth = WinGetClientSize($g_hGui)[0] Local $aParts = _GUICtrlStatusBar_GetParts($g_hStatus) _ArrayDelete($aParts, 0) Dim $g_aRatioW[Ubound($aParts)] For $i = 0 To UBound($aParts) - 1 $g_aRatioW[$i] = $aParts[$i] / $iGuiWidth Next EndFunc ;==>__GUIDarkMode_StatusRatio Func __GUIDarkMode_CreateSizebox() ; create grip $g_iHeight = WinGetPos($g_hStatus)[3] - 3 ;$g_hDots = CreateDots($g_iHeight, $g_iHeight, 0xFF000000 + $g_iBkColor, 0xFF000000 + $g_iTextColor) $g_hDots = CreateDots($g_hGripSize + 2, $g_hGripSize + 2, 0xFF000000 + $g_iBkColor, 0xFF000000 + $g_iTextColor) Local Const $SBS_SIZEBOX = 0x08, $SBS_SIZEGRIP = 0x10 ; Create a sizebox window (Scrollbar class) $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) $hSizeboxProc = DllCallbackRegister('__GUIDarkMode_SizeboxProc', 'lresult', 'hwnd;uint;wparam;lparam') $g_hOldProc = _WinAPI_SetWindowLong($g_hSizebox, $GWL_WNDPROC, DllCallbackGetPtr($hSizeboxProc)) $hCursor = _WinAPI_LoadCursor(0, $OCR_SIZENWSE) _WinAPI_SetClassLongEx($g_hSizebox, -12, $hCursor) ; $GCL_HCURSOR = -12 ; Fix Z-order of SizeboxProc (needed for cursor) Local $aPos = WinGetPos($g_hSizebox) _WinAPI_SetWindowPos($g_hSizebox, $HWND_TOP, $aPos[0], $aPos[1], $aPos[2], $aPos[3], 0) EndFunc ;==>__GUIDarkMode_CreateSizebox
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now