WildByDesign Posted Saturday at 12:13 PM Posted Saturday at 12:13 PM Dark Mode on Windows has many areas or specific combinations of things where certain controls have incomplete dark mode theming. 25H2 fixes this plus many other dark theme issues but that does not help the majority of users. Example: I kept this example script as small as possible to make it easier to help with the area that needs help. I already have other parts to the script that complete the proper functioning of the parts as well as the painting of the gripper dots over that bottom right corner courtesy of @pixelsearch and @Andreik. The functionality that paints the gripper dots also has the ability to paint a background. However, since that is in it's own "Scrollbar" window, it is not painted directly on the statusbar control. The reason why I need a FillRect directly on the statusbar control over that small square is because that is the only way that it will accept the Windows 11 materials such as Mica, Acrylic, etc. The size of that square is 16 pixels multiplied by the current DPI scale. Eg. 16 x 1.25 on 125%, 16 x 1.5 on 150% and so on. On 100% and 125% scaling, it is 2 pixels in from the right and 2 pixels up from the bottom of the window. On 150% scaling it is 3 pixels in from right and 3 pixels up from bottom. So I assume that it is doing 2 x the current DPI scale. Although for 125% scaling it seems to round down from 2.5 to 2 instead of rounding up. Anyway, if anybody knows how to get the position of that square, we should be able to do the FillRect in the _WM_DRAWITEM function. Thank you for your time. I appreciate it very much, always. Example script: expandcollapse popup#include <ButtonConstants.au3> #include <GUIConstantsEx.au3> #include <GuiStatusBar.au3> #include <WindowsConstants.au3> #include <Array.au3> #include <File.au3> #include <WinAPI.au3> ; DPI awareness DllCall("User32.dll", "bool", "SetProcessDpiAwarenessContext" , "HWND", "DPI_AWARENESS_CONTEXT" -2) Global $hStatus $Form1 = GUICreate("Form1", 615, 437, -1, -1, $WS_SYSMENU + $WS_MINIMIZEBOX + $WS_MAXIMIZEBOX + $WS_SIZEBOX) GUISetBkColor(0x202020) GUICtrlSetDefColor(0x202020) $hStatus = _GUICtrlStatusBar_Create($Form1) GUIRegisterMsg($WM_DRAWITEM, "_WM_DRAWITEM") ; Set parts Local $aParts[4] = [75, 150, 300, -1] _GUICtrlStatusBar_SetParts($hStatus, $aParts) _GUICtrlStatusBar_SetText($hStatus, "Part 0", 0, $SBT_OWNERDRAW) _GUICtrlStatusBar_SetText($hStatus, "Part 1", 1, $SBT_OWNERDRAW) _GUICtrlStatusBar_SetText($hStatus, "Part 2", 2, $SBT_OWNERDRAW) _GUICtrlStatusBar_SetText($hStatus, "Part 3", 3, $SBT_OWNERDRAW) Global $global_StatusBar_Text = " Part 1" ; apply dark mode to GUI DarkMode($Form1, True) ; apply dark theme to statusbar _WinAPI_SetWindowTheme_unr($hStatus, "DarkMode", "ExplorerStatusBar") GUISetState(@SW_SHOW) GUIRegisterMsg($WM_SIZE, "WM_SIZE") While 1 $nMsg = GUIGetMsg() Switch $nMsg Case $GUI_EVENT_CLOSE Exit EndSwitch WEnd ; Resize the status bar when GUI size changes Func WM_SIZE($hWnd, $iMsg, $wParam, $lParam) #forceref $hWnd, $iMsg, $wParam, $lParam _GUICtrlStatusBar_Resize($hStatus) Return $GUI_RUNDEFMSG EndFunc ;==>WM_SIZE Func _WM_DRAWITEM($hWnd, $Msg, $wParam, $lParam) #forceref $Msg, $wParam, $lParam Local $tDRAWITEMSTRUCT = DllStructCreate("uint CtlType;uint CtlID;uint itemID;uint itemAction;uint itemState;HWND hwndItem;HANDLE hDC;long rcItem[4];ULONG_PTR itemData", $lParam) If DllStructGetData($tDRAWITEMSTRUCT, "hwndItem") <> $hStatus Then Return $GUI_RUNDEFMSG ; Only process the statusbar Local $itemID = DllStructGetData($tDRAWITEMSTRUCT, "itemID") ;part number Local $hDC = DllStructGetData($tDRAWITEMSTRUCT, "hDC") Local $tRect = DllStructCreate("long left;long top;long right; long bottom", DllStructGetPtr($tDRAWITEMSTRUCT, "rcItem")) Local $iTop = DllStructGetData($tRect, "top") Local $iLeft = DllStructGetData($tRect, "left") Local $hBrush $hBrush = _WinAPI_CreateSolidBrush(0x000000) ; Backgound Color _WinAPI_FillRect($hDC, DllStructGetPtr($tRect), $hBrush) _WinAPI_SetTextColor($hDC, 0xFFFFFF) ; Font Color _WinAPI_SetBkMode($hDC, $TRANSPARENT) DllStructSetData($tRect, "top", $iTop + 1) DllStructSetData($tRect, "left", $iLeft + 1) _WinAPI_DrawText($hDC, $global_StatusBar_Text, $tRect, $DT_LEFT) _WinAPI_DeleteObject($hBrush) $tDRAWITEMSTRUCT = 0 Return $GUI_RUNDEFMSG EndFunc ;==>_WM_DRAWITEM ;-------------------------------------------------------------------------------------------------------------------------------- ; https://www.autoitscript.com/forum/topic/211475-darkmode-udf-for-autoits-win32guis/#comment-1530103 ;-------------------------------------------------------------------------------------------------------------------------------- Func DarkMode($hGUI, $bDarkMode = True) ; DarkMode Local Enum $DWMWA_USE_IMMERSIVE_DARK_MODE = (@OSBuild <= 18985) ? 19 : 20 ;ConsoleWrite("$DWMWA_USE_IMMERSIVE_DARK_MODE=" & $DWMWA_USE_IMMERSIVE_DARK_MODE & @CRLF) ; DWMWA_USE_IMMERSIVE_DARK_MODE ; https://learn.microsoft.com/en-us/windows/win32/api/dwmapi/ne-dwmapi-dwmwindowattribute ; Use with DwmSetWindowAttribute. Allows the window frame for this window to be drawn in dark mode colors when the dark mode system setting is enabled. ; For compatibility reasons, all windows default to light mode regardless of the system setting. ; The pvAttribute parameter points to a value of type BOOL. TRUE to honor dark mode for the window, FALSE to always use light mode. ; This value is supported starting with Windows 11 Build 22000. Local $iRet = _WinAPI_DwmSetWindowAttribute_unr($hGUI, $DWMWA_USE_IMMERSIVE_DARK_MODE, $bDarkMode) If Not $iRet Then Return SetError(1, 0, -1) ;_SetCtrlColorMode($Button_OK, $bDarkMode) ;_SetCtrlColorMode($Button_copy, $bDarkMode) _SetCtrlColorMode($hGUI, $bDarkMode) ;_WinAPI_SetWindowTheme_unr(GUICtrlGetHandle($ChbxDrkMode), 0, 0) ; this control needs the theme EndFunc ;==>DarkMode ;-------------------------------------------------------------------------------------------------------------------------------- Func _SetCtrlColorMode($hWnd, $bDarkMode = True, $sName = Default) ; 'Explorer', 'CFD', 'DarkMode_ItemsView', etc. If $sName = Default Then $sName = $bDarkMode ? 'DarkMode_Explorer' : 'Explorer' $bDarkMode = Not Not $bDarkMode ; https://www.vbforums.com/showthread.php?900444-Windows-10-Dark-Mode-amp-VB6-apps If Not IsHWnd($hWnd) Then $hWnd = GUICtrlGetHandle($hWnd) Local Enum $eDefault, $eAllowDark, $eForceDark, $eForceLight, $eMax ; enum PreferredAppMode DllCall('uxtheme.dll', 'bool', 133, 'hwnd', $hWnd, 'bool', $bDarkMode) ; fnAllowDarkModeForWindow = 133 DllCall('uxtheme.dll', 'int', 135, 'int', ($bDarkMode ? $eForceDark : $eForceLight)) ; fnAllowDarkModeForApp = 135 _WinAPI_SetWindowTheme_unr($hWnd, $sName) ; https://www.autoitscript.com/forum/index.php?showtopic=211475&view=findpost&p=1530103 DllCall('uxtheme.dll', 'none', 104) ; fnRefreshImmersiveColorPolicyState = 104 ; not needed ? _SendMessage($hWnd, $WM_THEMECHANGED, 0, 0) ; not needed ? EndFunc ;==>_SetCtrlColorMode ;-------------------------------------------------------------------------------------------------------------------------------- Func _WinAPI_SetWindowTheme_unr($hWnd, $sName = Null, $sList = Null) ; #include <WinAPITheme.au3> ; unthoughtful unrestricting mod. ;Causes a window to use a different set of visual style information than its class normally uses Local $sResult = DllCall('UxTheme.dll', 'long', 'SetWindowTheme', 'hwnd', $hWnd, 'wstr', $sName, 'wstr', $sList) If @error Then Return SetError(@error, @extended, 0) If $sResult[0] Then Return SetError(10, $sResult[0], 0) Return 1 EndFunc ;==>_WinAPI_SetWindowTheme_unr ;-------------------------------------------------------------------------------------------------------------------------------- Func _WinAPI_DwmSetWindowAttribute_unr($hWnd, $iAttribute, $iData) ; #include <WinAPIGdi.au3> ; unthoughtful unrestricting mod. ;Sets the value of the specified attributes for non-client rendering to apply to the window Local $aCall = DllCall('dwmapi.dll', 'long', 'DwmSetWindowAttribute', 'hwnd', $hWnd, 'dword', $iAttribute, _ 'dword*', $iData, 'dword', 4) If @error Then Return SetError(@error, @extended, 0) If $aCall[0] Then Return SetError(10, $aCall[0], 0) Return 1 EndFunc ;==>_WinAPI_DwmSetWindowAttribute_unr ;--------------------------------------------------------------------------------------------------------------------------------
Andreik Posted Saturday at 03:56 PM Posted Saturday at 03:56 PM Did you tried a combination of GetThemePosition() and GetThemePartSize() with SP_GRIPPER as theme part? WildByDesign 1
WildByDesign Posted Saturday at 04:05 PM Author Posted Saturday at 04:05 PM 6 minutes ago, Andreik said: Did you tried a combination of GetThemePosition() and GetThemePartSize() with SP_GRIPPER as theme part? No, I am not familiar with those functions at all so I haven’t tried them yet. I’m just looking up the details for them on the libfunctions page and those functions look appropriate. I will give them a try. Thank you.
WildByDesign Posted Saturday at 09:43 PM Author Posted Saturday at 09:43 PM There doesn't seem to be any examples for those functions in the help section or forum so I'm not entirely sure how to properly use them. I noticed that Notepad++ uses it. It's C++ though. Link: https://github.com/notepad-plus-plus/notepad-plus-plus/blob/master/PowerEditor/src/WinControls/StatusBar/StatusBar.cpp#L213-L222 { 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); }
WildByDesign Posted Sunday at 12:22 PM Author Posted Sunday at 12:22 PM 20 hours ago, Andreik said: Did you tried a combination of GetThemePosition() and GetThemePartSize() with SP_GRIPPER as theme part? I have spent a few hours trying these but not working yet. I have clearly made a mistake somewhere. I can get the theme handle, but any of the API calls result in error. Here is what I have for testing: expandcollapse popup#include <WindowsStylesConstants.au3> #include <GUIConstantsEx.au3> #include <GuiStatusBar.au3> #include <WinAPITheme.au3> ; DPI DllCall("User32.dll", "bool", "SetProcessDpiAwarenessContext" , "HWND", "DPI_AWARENESS_CONTEXT" -2) Global $g_hStatus, $hGUI Example() Func Example() ; Create GUI Local $hGUI = GUICreate("StatusBar Create (v" & @AutoItVersion & ")", 450, 320, 100, 100, $WS_OVERLAPPEDWINDOW) ; adjusts array to largest array passed in (this time the text array is the largest) Local $aText[3] = ["Part 0", "Part 1", "Part 2"] Local $aParts[2] = [100, 175] $g_hStatus = _GUICtrlStatusBar_Create($hGUI, $aParts, $aText) GUISetState(@SW_SHOW) themeData() ; Loop until the user exits. Do Until GUIGetMsg() = $GUI_EVENT_CLOSE GUIDelete($hGUI) EndFunc ;==>Example Func themeData() Local Const $SP_GRIPPERPANE = 2 Local Const $SP_GRIPPER = 3 ConsoleWrite("theme data check" & @CRLF) Local $hTheme = _WinAPI_OpenThemeData($hGUI, "Status") ConsoleWrite("theme handle: " & $hTheme & @CRLF) Local $iTest = _WinAPI_GetThemeMetric($hTheme, $SP_GRIPPER, Null, $TMT_WIDTH) If @error Then ConsoleWrite("Error on _WinAPI_GetThemeMetric" & @CRLF) Local $tPOINT = _WinAPI_GetThemePosition ($hTheme, $SP_GRIPPER, Null, $TMT_DEFAULTPANESIZE) If @error Then ConsoleWrite("Error on _WinAPI_GetThemePosition" & @CRLF) _WinAPI_CloseThemeData($hTheme) EndFunc I have tried both Null and 0 for the StateID. Apparently the statusbar theme parts have no states at all according to MS docs and header files.
Solution Andreik Posted Sunday at 10:56 PM Solution Posted Sunday at 10:56 PM Well it seems you can get just the size of the grip and you need to calculate the position. Is that what you need? expandcollapse popup#include <WindowsStylesConstants.au3> #include <GUIConstantsEx.au3> #include <GuiStatusBar.au3> #include <WinAPITheme.au3> #include <GDIPlus.au3> ; DPI DllCall("User32.dll", "bool", "SetProcessDpiAwarenessContext" , "HWND", "DPI_AWARENESS_CONTEXT" -2) Global $g_hStatus, $hGUI Example() Func Example() ; Create GUI Local $hGUI = GUICreate("StatusBar Create (v" & @AutoItVersion & ")", 450, 320, 100, 100, $WS_OVERLAPPEDWINDOW) ; adjusts array to largest array passed in (this time the text array is the largest) Local $aText[3] = ["Part 0", "Part 1", "Part 2"] Local $aParts[2] = [100, 175] $g_hStatus = _GUICtrlStatusBar_Create($hGUI, $aParts, $aText) GUISetState(@SW_SHOW) Sleep(2500) themeData() ; Loop until the user exits. Do Until GUIGetMsg() = $GUI_EVENT_CLOSE GUIDelete($hGUI) EndFunc ;==>Example Func themeData() Local Const $tagRECT = "struct; long Left;long Top;long Right;long Bottom; endstruct" Local Const $SP_GRIPPERPANE = 2 Local Const $SP_GRIPPER = 3 Local $hTheme = _WinAPI_OpenThemeData($hGUI, "Status") Local $tSIZE = _WinAPI_GetThemePartSize($hTheme, $SP_GRIPPER, 0, Null, Null, 1) _WinAPI_CloseThemeData($hTheme) Local $aSBSize = WinGetClientSize($g_hStatus) Local $aBorders = _GUICtrlStatusBar_GetBorders($g_hStatus) Local $tGripRect = DllStructCreate($tagRECT) $tGripRect.Right = $aSBSize[0] - $aBorders[0] $tGripRect.Bottom = $aSBSize[1] - $aBorders[1] $tGripRect.Left = $tGripRect.Right - $tSIZE.X $tGripRect.Top = $tGripRect.Bottom - $tSIZE.Y Local $hDC = _WinAPI_GetDC($g_hStatus) Local $hBrush = _WinAPI_CreateSolidBrush(0x0000FF) _WinAPI_FillRect($hDC, $tGripRect, $hBrush) _WinAPI_DeleteObject($hBrush) _WinAPI_ReleaseDC($g_hStatus, $hDC) EndFunc
Nine Posted Sunday at 11:20 PM Posted Sunday at 11:20 PM @WildByDesign btw, it doesn't change anything but you have still make the same mistake. Declaring a global var, then declaring it local. Gladly, having a 0 hWnd seems to be equal to active hWnd. My suggestion, always try to remove all unnecessary global variables as much as possible. In this case it was quite easy to accomplish... “They did not know it was impossible, so they did it” ― Mark Twain Spoiler Block all input without UAC Save/Retrieve Images to/from Text Monitor Management (VCP commands) Tool to search in text (au3) files Date Range Picker Virtual Desktop Manager Sudoku Game 2020 Overlapped Named Pipe IPC HotString 2.0 - Hot keys with string x64 Bitwise Operations Multi-keyboards HotKeySet Recursive Array Display Fast and simple WCD IPC Multiple Folders Selector Printer Manager GIF Animation (cached) Debug Messages Monitor UDF Screen Scraping Round Corner GUI UDF Multi-Threading Made Easy Interface Object based on Tag
WildByDesign Posted yesterday at 12:09 AM Author Posted yesterday at 12:09 AM 1 hour ago, Andreik said: Well it seems you can get just the size of the grip and you need to calculate the position. Is that what you need? This is exactly what I was attempting to achieve, although I was quite far away from figuring it out. Your example works perfectly. Thank you so much for your time and help with this. Also, thanks to you there is now a working example of the _WinAPI_GetThemePartSize function in the forum that can help anybody else in the future searching for similar functionality. 44 minutes ago, Nine said: btw, it doesn't change anything but you have still make the same mistake. Declaring a global var, then declaring it local. Gladly, having a 0 hWnd seems to be equal to active hWnd. My suggestion, always try to remove all unnecessary global variables as much as possible. In this case it was quite easy to accomplish... You're right. I copy and pasted the example from the help files and carelessly added Global while forgetting to remove the Local declaration. That seems to be a common mistake that I keep making. Not so much in my own scripts, but when I try to quickly put together a smaller script for the purpose of asking for help in the forum, I try to get it done too quickly and don't look over it well enough. Limiting unnecessary Global variables is a great idea. I will definitely keep that in mind. I would like to practice making more use of passing variables between functions also to limit Global as much as possible.
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