Popular Post WildByDesign Posted Tuesday at 05:35 PM Popular Post Posted Tuesday at 05:35 PM (edited) This UDF was created within the DarkMode UDF for AutoIt's Win32GUIs thread which was originally created by @NoNameCode. I ended up extending the features quite significantly and therefore decided to branch off into a new thread because I do not want to take anything away from the original DarkMode UDF. Goal: My goal was to make everything as automated and as simple as possible. I wanted it so that whoever is using it can just add one line of code _GUIDarkTheme_ApplyDark($hGUI, True) just before their already existing GUISetState() function. This would initiate the dark mode and automatically detect all controls, convert to dark mode and use the necessary subclassing whenever needed. Community: This UDF contains a lot of code from throughout the amazing AutoIt community and therefore belongs to every single one of us. I am always welcome to any suggestions and collaboration. Changelog: Spoiler GUIDarkTheme 1.2.0: GUIDarkTheme and GUIDarkMenu have been combined Added new function _GUIDarkTheme_ApplyMaterial() for applying Windows 11 materials (Mica, Acrylic, etc.) SampleControls-ModernDark example has been updated to show material effect Requires Windows 11 build 22621 or higher GUIDarkTheme 1.2.1: Add TVS_EX_DOUBLEBUFFER extended style to TreeView controls GUIDarkTheme-1.2.0.7z GUIDarkTheme-1.2.1.7z Edited Tuesday at 08:55 PM by WildByDesign Andreik, ioa747, mLipok and 2 others 5
Andreik Posted Tuesday at 07:16 PM Posted Tuesday at 07:16 PM I like the idea of calling a single function and turn everything dark. It seems to work fine in most cases but for tree views some visual artifacts appear. Anyone else experiencing this? argumentum and WildByDesign 2
WildByDesign Posted Tuesday at 08:11 PM Author Posted Tuesday at 08:11 PM I haven’t seen it before, but I’m thinking maybe adding doublebuffer to the TreeView control should fix it. I can have that applied through the UDF. I will post an update later with doublebuffer applied to see if it helps.
argumentum Posted Tuesday at 08:13 PM Posted Tuesday at 08:13 PM (edited) Edited Tuesday at 08:14 PM by argumentum Follow the link to my code contribution ( and other things too ). FAQ - Please Read Before Posting.
argumentum Posted Tuesday at 08:19 PM Posted Tuesday at 08:19 PM ..yes, after a repaint. Minimize it and restore it and there it is. WildByDesign 1 Follow the link to my code contribution ( and other things too ). FAQ - Please Read Before Posting.
WildByDesign Posted Tuesday at 08:52 PM Author Posted Tuesday at 08:52 PM I cannot reproduce the artifact issue on my main system. I just uploaded version 1.2.1 which automatically adds TVS_EX_DOUBLEBUFFER to any TreeView controls. Can you both please test it and see if it helps with this issue?
argumentum Posted Tuesday at 09:15 PM Posted Tuesday at 09:15 PM ..same "washing" WildByDesign 1 Follow the link to my code contribution ( and other things too ). FAQ - Please Read Before Posting.
argumentum Posted Tuesday at 09:19 PM Posted Tuesday at 09:19 PM 1 hour ago, argumentum said: That was because I wasn't using a standard Windows setup while testing WildByDesign 1 Follow the link to my code contribution ( and other things too ). FAQ - Please Read Before Posting.
Andreik Posted Tuesday at 09:49 PM Posted Tuesday at 09:49 PM 56 minutes ago, WildByDesign said: Can you both please test it and see if it helps with this issue? Looks good to me. WildByDesign 1
UEZ Posted Tuesday at 11:38 PM Posted Tuesday at 11:38 PM (edited) You can overpaint the size grips in edit, listvew and treeview. I used in my example $WM_PAINT in _SubclassProc function: expandcollapse popup... Case $WM_PAINT Local $sClass = StringLower(_WinAPI_GetClassName($hWnd)) If $sClass = "syslistview32" Or $sClass = "systreeview32" Or $sClass = "edit" Then ; hide Sizegrip boxes Local $iRet = _WinAPI_DefSubclassProc($hWnd, $iMsg, $wParam, $lParam) ; Overpaint sizegrip boxes if visible Local $iWinStyle = _WinAPI_GetWindowLong($hWnd, $GWL_STYLE) If BitAND($iWinStyle, $WS_HSCROLL) And BitAND($iWinStyle, $WS_VSCROLL) Then Local $hDC = _WinAPI_GetWindowDC($hWnd) ; GetWindowDC statt GetDC! Local $tWnd = _WinAPI_GetWindowRect($hWnd) Local $tClient = _WinAPI_GetClientRect($hWnd) Local $iScrollW = _WinAPI_GetSystemMetrics($SM_CXVSCROLL) Local $iScrollH = _WinAPI_GetSystemMetrics($SM_CYHSCROLL) ; convert client-area to Window coordinates Local $tPt = DllStructCreate($tagPOINT) $tPt.X = $tClient.right $tPt.Y = $tClient.bottom DllCall("user32.dll", "bool", "ClientToScreen", "hwnd", $hWnd, "struct*", $tPt) ; direct relativ coordinates Local $tCorner = DllStructCreate($tagRECT), $delta = (_WinAPI_GetWindowLong($hWnd, $GWL_EXSTYLE) And $WS_EX_CLIENTEDGE ? 4 : 1) $tCorner.left = $tClient.right + $delta $tCorner.top = $tClient.bottom + $delta $tCorner.right = $tCorner.left + $iScrollW $tCorner.bottom = $tCorner.top + $iScrollH Local $hBrush = _WinAPI_CreateSolidBrush(_ColorToCOLORREF($COLOR_TITLE_DARK)) _WinAPI_FillRect($hDC, $tCorner, $hBrush) _WinAPI_DeleteObject($hBrush) _WinAPI_ReleaseDC($hWnd, $hDC) EndIf Return $iRet Else Return _WinAPI_DefSubclassProc($hWnd, $iMsg, $wParam, $lParam) EndIf ... I didn't test it for DPI <> 1 aka 96 if $tCorner is properly calculated. Edited Tuesday at 11:39 PM by UEZ WildByDesign 1 Please don't send me any personal message and ask for support! I will not reply! Selection of finest graphical examples at Codepen.io The own fart smells best! ✌Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!¯\_(ツ)_/¯ ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ
jpm Posted Wednesday at 07:36 AM Posted Wednesday at 07:36 AM It is for me almost perfect for the modern darkmode the border are too strong for listview can you tidies all .au3 with Scite Ctrl-T ? Cheers WildByDesign 1
WildByDesign Posted Wednesday at 10:50 AM Author Posted Wednesday at 10:50 AM 11 hours ago, UEZ said: You can overpaint the size grips in edit, listvew and treeview. I used in my example $WM_PAINT in _SubclassProc function: This is fantastic. Thank you. Painting over the size grips for those controls is a subtle but nice added touch to the overall look. I will have to overhaul my subclassing methods to apply this change so it may take a few days. I appreciate it. I do have a question for you. I've been meaning to ask you this for a few days now: How could we subclass multiple ListView headers? For example, if a user chooses to use this UDF in a project with multiple ListView controls. There are many ListView header subclassing examples in the forum, but they all target one specific handle. I like the technique that you use based on class name: If $iCode = $NM_CUSTOMDRAW And StringLower(__WinAPI_GetClassName($hWndFrom)) = "msctls_trackbar32" Then I was able to successfully use that same technique for the date time picker control: If __WinAPI_GetClassName($hWndFrom) = "SysDateTimePick32" Then I did try to use the same technique for SysListView32 class but it failed to subclass the ListView header. I was able to confirm that I was obtaining the correct header handle for each ListView. Do you know if it is possible to use this same class name technique to support subclassing multiple ListView headers?
WildByDesign Posted Wednesday at 10:53 AM Author Posted Wednesday at 10:53 AM 3 hours ago, jpm said: It is for me almost perfect for the modern darkmode the border are too strong for listview I agree. Some of the newer control themes from Windows 11 (24H2/25H2) DarkMode_DarkTheme look better, while some look worse. I will change the ListView to use the older DarkMode_Explorer theme since the border is less contrast. 3 hours ago, jpm said: can you tidies all .au3 with Scite Ctrl-T ? Yes, absolutely. I will have to make a habit for myself to ensure that I run Tidy before each release.
WildByDesign Posted Wednesday at 10:55 AM Author Posted Wednesday at 10:55 AM (edited) 14 hours ago, argumentum said: ..same "washing" Thanks for letting me know. That sizebox definitely should not be showing like that. I'll look into painting over the others as well. EDIT: Actually, now that I think of it, is that the ModernDark example? I have a feeling that I may not have the right background color for the sizebox because I change most of the colors when materials are applied. Edited Wednesday at 11:54 AM by WildByDesign
UEZ Posted Wednesday at 01:08 PM Posted Wednesday at 01:08 PM 2 hours ago, WildByDesign said: This is fantastic. Thank you. Painting over the size grips for those controls is a subtle but nice added touch to the overall look. I will have to overhaul my subclassing methods to apply this change so it may take a few days. I appreciate it. I do have a question for you. I've been meaning to ask you this for a few days now: How could we subclass multiple ListView headers? For example, if a user chooses to use this UDF in a project with multiple ListView controls. There are many ListView header subclassing examples in the forum, but they all target one specific handle. I like the technique that you use based on class name: If $iCode = $NM_CUSTOMDRAW And StringLower(__WinAPI_GetClassName($hWndFrom)) = "msctls_trackbar32" Then I was able to successfully use that same technique for the date time picker control: If __WinAPI_GetClassName($hWndFrom) = "SysDateTimePick32" Then I did try to use the same technique for SysListView32 class but it failed to subclass the ListView header. I was able to confirm that I was obtaining the correct header handle for each ListView. Do you know if it is possible to use this same class name technique to support subclassing multiple ListView headers? To handle all headers generically you need something like my _SubclassProc() and NM_CUSTOMDRAW notification to manage ListView headers. Since $hWndFrom contains the actual handle of the sending control, the StringLower(_WinAPI_GetClassName($hWndFrom)) = "sysheader32" check automatically matches all ListView headers regardless of how many ListViews you have. If you need per-ListView differentiation, you can check the header's parent: Case "sysheader32" ; Optionally identify which ListView this header belongs to: Local $hParentListView = _WinAPI_GetParent($hFrom) ; Apply different colors per ListView if needed ; Otherwise the generic class name check handles all of them uniformly I hope it helps you. WildByDesign 1 Please don't send me any personal message and ask for support! I will not reply! Selection of finest graphical examples at Codepen.io The own fart smells best! ✌Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!¯\_(ツ)_/¯ ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ
WildByDesign Posted Wednesday at 11:55 PM Author Posted Wednesday at 11:55 PM (edited) 10 hours ago, UEZ said: To handle all headers generically you need something like my _SubclassProc() and NM_CUSTOMDRAW notification to manage ListView headers. Since $hWndFrom contains the actual handle of the sending control, the StringLower(_WinAPI_GetClassName($hWndFrom)) = "sysheader32" check automatically matches all ListView headers regardless of how many ListViews you have. This was very helpful, thank you. I was able to get a subclass procedure working (similar to yours) and it is subclassing multiple ListView headers perfectly now. So this is great and I plan to expand on it some more now that I understand how it works better. Are there limitations to what types of controls can be added to the _SubclassProc() function? For example, since the slider control (msctls_trackbar32) subclassing also uses WM_NOTIFY, I was hoping that I could add it using the same technique. However, it failed for me. Using GUIRegisterMsg($WM_NOTIFY, "_WM_NOTIFY") does work, but using _SubclassProc() instead does not seem to work for me. Edited Wednesday at 11:56 PM by WildByDesign
UEZ Posted yesterday at 11:09 AM Posted yesterday at 11:09 AM (edited) 12 hours ago, WildByDesign said: Are there limitations to what types of controls can be added to the _SubclassProc() function? Any control that has its own HWND can be subclassed. 12 hours ago, WildByDesign said: For example, since the slider control (msctls_trackbar32) subclassing also uses WM_NOTIFY, I was hoping that I could add it using the same technique. However, it failed for me. Using GUIRegisterMsg($WM_NOTIFY, "_WM_NOTIFY") does work, but using _SubclassProc() instead does not seem to work for me. WM_NOTIFY is always sent upward - from the control to its parent window. When you subclass the trackbar itself, you're watching messages sent to the trackbar - but WM_NOTIFY from the trackbar is sent away from it, never back into it. The trackbar will never see its own WM_NOTIFY. GUIRegisterMsg works because it hooks into the main GUI window's message pump, which is exactly where those notifications land. You need to attach the subclass proc to the parent HWND (your GUI), not the trackbar: ; Subclass the main GUI window to catch child-control notifications Local $hGUI = GUICreate("Test", 400, 300) Local $hSlider = GUICtrlCreateSlider(10, 10, 200, 30) Local $hSliderHWND = GUICtrlGetHandle($hSlider) _WinAPI_SetWindowSubclass(WinGetHandle($hGUI), $g_pSubclassProc, 1, 0) Then inside _SubclassProc, branch on $hFrom to identify which child sent the notification: ... Case $WM_NOTIFY Local $tNMHDR = DllStructCreate($tagNMHDR, $lParam) Local $hFrom = $tNMHDR.hWndFrom Local $iCode = $tNMHDR.Code Switch StringLower(_WinAPI_GetClassName($hFrom)) Case "sysheader32" ; ... existing header handling Case "msctls_trackbar32" Switch $iCode Case $TRBN_THUMBPOSCHANGING ; handle slider EndSwitch EndSwitch ... Edited yesterday at 12:06 PM by UEZ WildByDesign 1 Please don't send me any personal message and ask for support! I will not reply! Selection of finest graphical examples at Codepen.io The own fart smells best! ✌Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!¯\_(ツ)_/¯ ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ
WildByDesign Posted yesterday at 11:56 AM Author Posted yesterday at 11:56 AM 37 minutes ago, UEZ said: WM_NOTIFY is always sent upward — from the control to its parent window. When you subclass the trackbar itself, you're watching messages sent to the trackbar — but WM_NOTIFY from the trackbar is sent away from it, never back into it. The trackbar will never see its own WM_NOTIFY. GUIRegisterMsg works because it hooks into the main GUI window's message pump, which is exactly where those notifications land. I know that English is not your first language, from my understanding. However, you have excellent teaching skills! You explained that in such a way that I was able to understand and learn from very quickly. Much of that was a mystery to me before. I appreciate how gracious you are with your time to help others. Cheers! 🍷 Following your suggestions, everything is working perfectly now. And now that I understand how it works, I should be able to add more controls in a well organized way. Since my method runs through all of the window/control handles to auto-detect, I just added the _WinAPI_SetWindowSubclass() function under the 'AutoIt v3 GUI' case. Although I should probably add some checks to ensure that it is only done with top-level window and not any child GUI windows. I haven't looked into it that far yet. What was interesting to me, though, is that I was able to remove _WinAPI_SetWindowSubclass() from the 'msctls_trackbar32' case/control and it still subclasses perfectly. But as you said, it would be because of the direction that those window messages go. I still have a lot to learn but this is very interesting.
UEZ Posted yesterday at 12:15 PM Posted yesterday at 12:15 PM As far as I'm concerned, the DarkMode project is complete for now. You're well on your way to building a great UDF! Keep it up. 16 minutes ago, WildByDesign said: I know that English is not your first language, from my understanding. That's right. I usually have to switch back and forth between three languages every day, which isn't easy, but there are some great tools out there that make the work easier when it comes to phrasing things. 😉 WildByDesign and argumentum 1 1 Please don't send me any personal message and ask for support! I will not reply! Selection of finest graphical examples at Codepen.io The own fart smells best! ✌Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!¯\_(ツ)_/¯ ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ
WildByDesign Posted yesterday at 01:29 PM Author Posted yesterday at 01:29 PM (edited) @UEZ There are two other questions that I have wanted to ask you for a while now: I notice that you quite often use StringLower in your switches when comparing class names in a few areas. Is this a choice specifically for improving performance of running through the switches? Regarding window procedure functions. We can have many individual window procedure functions for different controls or we can have one big window procedure function for all subclassed controls. Would there be any difference in overall performance? Edited yesterday at 01:30 PM by WildByDesign
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