DarkMode (Force or Toggle)

Put simple Tips and Tricks that are not entire Tutorials in this forum
User avatar
jNizM
Posts: 3183
Joined: 30 Sep 2013, 01:33
Contact:

DarkMode (Force or Toggle)

09 Apr 2023, 06:38

This is more a Proof of the concept.

If someone with interest and good knowledge of the v2 classes, feel free to extends this into AHK's "class Gui" so its easy to use for others.

You can easy toggle between DarkMode and the Default Theme while the GUI is running. (Try this code and toggle with the radio button)
No need to manually adjust font colors or backgrounds when creating the GUI.

Todo:
- Font color of LV_Header
- ListView Scrollbars needs some workarounds (https://gist.github.com/ericoporto/1745f4b912e22f9eabfce2c7166d979b#dark-scrollbars)
- Font color of Checkboxes and Radios (atm I use a "fake" one - create controls without text and create a separat text control)
- Check more controls

Code: Select all

#Requires AutoHotkey v2.0


Main := Gui()

; call dark mode for window title + menu
SetWindowAttribute(Main)

Main.AddText("xm ym w300 0x200", "Static Control")
Main.AddEdit("xm y+10 w300", "Edit Control")
Main.AddEdit("xm y+10 w300", "Edit Control + UpDown")
Main.AddUpDown()
Main.AddEdit("xm y+10 w300 r3", "Multi-Line Edit Control")
Main.AddDropDownList("xm y+10 w300 Choose1", ["DDL Control", "DDL 2", "DDL 3"])
Main.AddComboBox("xm y+10 w300 Choose1", ["CB Control", "CB 2", "CB 3"])
Main.AddCheckBox("xm y+10 w300", "CheckBox")
SGW := SysGet(SM_CXMENUCHECK := 71)
SGH := SysGet(SM_CYMENUCHECK := 72)
Main.AddCheckBox("xm y+10 Checked h" SGH " w" SGW)
Main.AddText("x+1 yp 0x200 h" SGH, "Fake Checkbox")
Main.AddCheckBox("xm y+10 w300 Check3 CheckedGray", "CheckBox CheckedGray")
Main.AddButton("xm y+10 w300", "Button")
Main.AddRadio("xm y+10 w300 Group Checked", "DarkMode").OnEvent("Click", ToggleTheme)
Main.AddRadio("xm y+10 w300", "LightMode").OnEvent("Click", ToggleTheme)
LV := Main.AddListView("x+10 ym w300 r10", ["LV 1", "LV 2", "LV 3"])
loop 11
	LV.Add("", A_Index, A_Index, A_Index)
LB_Entries := Array()
loop 11
	LB_Entries.Push("LB " A_Index)
Main.AddListBox("xp y+10 w300 r10", LB_Entries)
Main.OnEvent("Close", (*) =>  ExitApp)

; call dark mode for controls
SetWindowTheme(Main)

Main.Show("AutoSize")




ToggleTheme(GuiCtrlObj, *)
{
	switch GuiCtrlObj.Text
	{
		case "DarkMode":
		{
			SetWindowAttribute(Main)
			SetWindowTheme(Main)
		}
		default:
		{
			SetWindowAttribute(Main, False)
			SetWindowTheme(Main, False)
		}
	}
}




SetWindowAttribute(GuiObj, DarkMode := True)
{
	global DarkColors          := Map("Background", "0x202020", "Controls", "0x404040", "Font", "0xE0E0E0")
	global TextBackgroundBrush := DllCall("gdi32\CreateSolidBrush", "UInt", DarkColors["Background"], "Ptr")
	static PreferredAppMode    := Map("Default", 0, "AllowDark", 1, "ForceDark", 2, "ForceLight", 3, "Max", 4)

	if (VerCompare(A_OSVersion, "10.0.17763") >= 0)
	{
		DWMWA_USE_IMMERSIVE_DARK_MODE := 19
		if (VerCompare(A_OSVersion, "10.0.18985") >= 0)
		{
			DWMWA_USE_IMMERSIVE_DARK_MODE := 20
		}
		uxtheme := DllCall("kernel32\GetModuleHandle", "Str", "uxtheme", "Ptr")
		SetPreferredAppMode := DllCall("kernel32\GetProcAddress", "Ptr", uxtheme, "Ptr", 135, "Ptr")
		FlushMenuThemes     := DllCall("kernel32\GetProcAddress", "Ptr", uxtheme, "Ptr", 136, "Ptr")
		switch DarkMode
		{
			case True:
			{
				DllCall("dwmapi\DwmSetWindowAttribute", "Ptr", GuiObj.hWnd, "Int", DWMWA_USE_IMMERSIVE_DARK_MODE, "Int*", True, "Int", 4)
				DllCall(SetPreferredAppMode, "Int", PreferredAppMode["ForceDark"])
				DllCall(FlushMenuThemes)
				GuiObj.BackColor := DarkColors["Background"]
			}
			default:
			{
				DllCall("dwmapi\DwmSetWindowAttribute", "Ptr", GuiObj.hWnd, "Int", DWMWA_USE_IMMERSIVE_DARK_MODE, "Int*", False, "Int", 4)
				DllCall(SetPreferredAppMode, "Int", PreferredAppMode["Default"])
				DllCall(FlushMenuThemes)
				GuiObj.BackColor := "Default"
			}
		}
	}
}


SetWindowTheme(GuiObj, DarkMode := True)
{
	static GWL_WNDPROC        := -4
	static GWL_STYLE          := -16
	static ES_MULTILINE       := 0x0004
	static LVM_GETTEXTCOLOR   := 0x1023
	static LVM_SETTEXTCOLOR   := 0x1024
	static LVM_GETTEXTBKCOLOR := 0x1025
	static LVM_SETTEXTBKCOLOR := 0x1026
	static LVM_GETBKCOLOR     := 0x1000
	static LVM_SETBKCOLOR     := 0x1001
	static LVM_GETHEADER      := 0x101F
	static GetWindowLong      := A_PtrSize = 8 ? "GetWindowLongPtr" : "GetWindowLong"
	static SetWindowLong      := A_PtrSize = 8 ? "SetWindowLongPtr" : "SetWindowLong"
	static Init               := False
	static LV_Init            := False
	global IsDarkMode         := DarkMode

	Mode_Explorer  := (DarkMode ? "DarkMode_Explorer"  : "Explorer" )
	Mode_CFD       := (DarkMode ? "DarkMode_CFD"       : "CFD"      )
	Mode_ItemsView := (DarkMode ? "DarkMode_ItemsView" : "ItemsView")

	for hWnd, GuiCtrlObj in GuiObj
	{
		switch GuiCtrlObj.Type
		{
			case "Button", "CheckBox", "ListBox", "UpDown":
			{
				DllCall("uxtheme\SetWindowTheme", "Ptr", GuiCtrlObj.hWnd, "Str", Mode_Explorer, "Ptr", 0)
			}
			case "ComboBox", "DDL":
			{
				DllCall("uxtheme\SetWindowTheme", "Ptr", GuiCtrlObj.hWnd, "Str", Mode_CFD, "Ptr", 0)
			}
			case "Edit":
			{
				if (DllCall("user32\" GetWindowLong, "Ptr", GuiCtrlObj.hWnd, "Int", GWL_STYLE) & ES_MULTILINE)
				{
					DllCall("uxtheme\SetWindowTheme", "Ptr", GuiCtrlObj.hWnd, "Str", Mode_Explorer, "Ptr", 0)
				}
				else
				{
					DllCall("uxtheme\SetWindowTheme", "Ptr", GuiCtrlObj.hWnd, "Str", Mode_CFD, "Ptr", 0)
				}
			}
			case "ListView":
			{
				if !(LV_Init)
				{
					static LV_TEXTCOLOR   := SendMessage(LVM_GETTEXTCOLOR,   0, 0, GuiCtrlObj.hWnd)
					static LV_TEXTBKCOLOR := SendMessage(LVM_GETTEXTBKCOLOR, 0, 0, GuiCtrlObj.hWnd)
					static LV_BKCOLOR     := SendMessage(LVM_GETBKCOLOR,     0, 0, GuiCtrlObj.hWnd)
					LV_Init := True
				}
				GuiCtrlObj.Opt("-Redraw")
				switch DarkMode
				{
					case True:
					{
						SendMessage(LVM_SETTEXTCOLOR,   0, DarkColors["Font"],       GuiCtrlObj.hWnd)
						SendMessage(LVM_SETTEXTBKCOLOR, 0, DarkColors["Background"], GuiCtrlObj.hWnd)
						SendMessage(LVM_SETBKCOLOR,     0, DarkColors["Background"], GuiCtrlObj.hWnd)
					}
					default:
					{
						SendMessage(LVM_SETTEXTCOLOR,   0, LV_TEXTCOLOR,   GuiCtrlObj.hWnd)
						SendMessage(LVM_SETTEXTBKCOLOR, 0, LV_TEXTBKCOLOR, GuiCtrlObj.hWnd)
						SendMessage(LVM_SETBKCOLOR,     0, LV_BKCOLOR,     GuiCtrlObj.hWnd)
					}
				}
				DllCall("uxtheme\SetWindowTheme", "Ptr", GuiCtrlObj.hWnd, "Str", Mode_Explorer, "Ptr", 0)
				
				; To color the selection - scrollbar turns back to normal
				;DllCall("uxtheme\SetWindowTheme", "Ptr", GuiCtrlObj.hWnd, "Str", Mode_ItemsView, "Ptr", 0)

				; Header Text needs some NM_CUSTOMDRAW coloring
				LV_Header := SendMessage(LVM_GETHEADER, 0, 0, GuiCtrlObj.hWnd)
				DllCall("uxtheme\SetWindowTheme", "Ptr", LV_Header, "Str", Mode_ItemsView, "Ptr", 0)
				GuiCtrlObj.Opt("+Redraw")
			}
		}
	}

	if !(Init)
	{
		; https://www.autohotkey.com/docs/v2/lib/CallbackCreate.htm#ExSubclassGUI
		global WindowProcNew := CallbackCreate(WindowProc)  ; Avoid fast-mode for subclassing.
		global WindowProcOld := DllCall("user32\" SetWindowLong, "Ptr", GuiObj.Hwnd, "Int", GWL_WNDPROC, "Ptr", WindowProcNew, "Ptr")
		Init := True
	}
}



WindowProc(hwnd, uMsg, wParam, lParam)
{
	critical
	static WM_CTLCOLOREDIT    := 0x0133
	static WM_CTLCOLORLISTBOX := 0x0134
	static WM_CTLCOLORBTN     := 0x0135
	static WM_CTLCOLORSTATIC  := 0x0138
	static DC_BRUSH           := 18

	if (IsDarkMode)
	{
		switch uMsg
		{
			case WM_CTLCOLOREDIT, WM_CTLCOLORLISTBOX:
			{
				DllCall("gdi32\SetTextColor", "Ptr", wParam, "UInt", DarkColors["Font"])
				DllCall("gdi32\SetBkColor", "Ptr", wParam, "UInt", DarkColors["Controls"])
				DllCall("gdi32\SetDCBrushColor", "Ptr", wParam, "UInt", DarkColors["Controls"], "UInt")
				return DllCall("gdi32\GetStockObject", "Int", DC_BRUSH, "Ptr")
			}
			case WM_CTLCOLORBTN:
			{
				DllCall("gdi32\SetDCBrushColor", "Ptr", wParam, "UInt", DarkColors["Background"], "UInt")
				return DllCall("gdi32\GetStockObject", "Int", DC_BRUSH, "Ptr")
			}
			case WM_CTLCOLORSTATIC:
			{
				DllCall("gdi32\SetTextColor", "Ptr", wParam, "UInt", DarkColors["Font"])
				DllCall("gdi32\SetBkColor", "Ptr", wParam, "UInt", DarkColors["Background"])
				return TextBackgroundBrush
			}
		}
	}
	return DllCall("user32\CallWindowProc", "Ptr", WindowProcOld, "Ptr", hwnd, "UInt", uMsg, "Ptr", wParam, "Ptr", lParam)
}
DarkMode
Image

LightMode (default Theme)
Image


Some ref-links:
- https://github.com/ysc3839/win32-darkmode/tree/master/win32-darkmode
- https://gist.github.com/ericoporto/1745f4b912e22f9eabfce2c7166d979b
- https://github.com/tablacus/TablacusDark/wiki
- https://github.com/notepad-plus-plus/notepad-plus-plus/tree/master/PowerEditor/src/DarkMode
- https://github.com/notepad-plus-plus/notepad-plus-plus/blob/master/PowerEditor/src/NppDarkMode.cpp
[AHK] v2.0.5 | [WIN] 11 Pro (Version 22H2) | [GitHub] Profile
User avatar
jNizM
Posts: 3183
Joined: 30 Sep 2013, 01:33
Contact:

Re: DarkMode (Force or Toggle)

09 Apr 2023, 10:30

Another possibility would be to save the last selected option (DarkMode or LightMode) in the datastream of the script/exe and query it at startup.

Code: Select all

#Requires AutoHotkey v2.0


IsDarkMode := ADS.Load("DarkMode") ? True : False

Main := Gui()

; call dark mode for window title + menu
SetWindowAttribute(Main, IsDarkMode)

Main.AddText("xm ym w300 0x200", "Static Control")
Main.AddEdit("xm y+10 w300", "Edit Control")
Main.AddEdit("xm y+10 w300", "Edit Control + UpDown")
Main.AddUpDown()
Main.AddEdit("xm y+10 w300 r3", "Multi-Line Edit Control")
Main.AddDropDownList("xm y+10 w300 Choose1", ["DDL Control", "DDL 2", "DDL 3"])
Main.AddComboBox("xm y+10 w300 Choose1", ["CB Control", "CB 2", "CB 3"])
Main.AddCheckBox("xm y+10 w300", "CheckBox")
SGW := SysGet(SM_CXMENUCHECK := 71)
SGH := SysGet(SM_CYMENUCHECK := 72)
Main.AddCheckBox("xm y+10 Checked h" SGH " w" SGW)
Main.AddText("x+1 yp 0x200 h" SGH, "Fake Checkbox")
Main.AddCheckBox("xm y+10 w300 Check3 CheckedGray", "CheckBox CheckedGray")
Main.AddButton("xm y+10 w300", "Button")
Main.AddRadio("xm y+10 w300 Group " (IsDarkMode ? "Checked" : ""), "DarkMode").OnEvent("Click", ToggleTheme)
Main.AddRadio("xm y+10 w300 " (IsDarkMode ? "" : "Checked"), "LightMode").OnEvent("Click", ToggleTheme)
LV := Main.AddListView("x+10 ym w300 r10", ["LV 1", "LV 2", "LV 3"])
loop 11
	LV.Add("", A_Index, A_Index, A_Index)
LB_Entries := Array()
loop 11
	LB_Entries.Push("LB " A_Index)
Main.AddListBox("xp y+10 w300 r10", LB_Entries)
Main.OnEvent("Close", (*) =>  ExitApp)

; call dark mode for controls
SetWindowTheme(Main, IsDarkMode)

Main.Show("AutoSize")




ToggleTheme(GuiCtrlObj, *)
{
	switch GuiCtrlObj.Text
	{
		case "DarkMode":
		{
			SetWindowAttribute(Main)
			SetWindowTheme(Main)
			ADS.Save("DarkMode")
		}
		default:
		{
			SetWindowAttribute(Main, False)
			SetWindowTheme(Main, False)
			ADS.Reset()
		}
	}
}




SetWindowAttribute(GuiObj, DarkMode := True)
{
	global DarkColors          := Map("Background", "0x202020", "Controls", "0x404040", "Font", "0xE0E0E0")
	global TextBackgroundBrush := DllCall("gdi32\CreateSolidBrush", "UInt", DarkColors["Background"], "Ptr")
	static PreferredAppMode    := Map("Default", 0, "AllowDark", 1, "ForceDark", 2, "ForceLight", 3, "Max", 4)

	if (VerCompare(A_OSVersion, "10.0.17763") >= 0)
	{
		DWMWA_USE_IMMERSIVE_DARK_MODE := 19
		if (VerCompare(A_OSVersion, "10.0.18985") >= 0)
		{
			DWMWA_USE_IMMERSIVE_DARK_MODE := 20
		}
		uxtheme := DllCall("kernel32\GetModuleHandle", "Str", "uxtheme", "Ptr")
		SetPreferredAppMode := DllCall("kernel32\GetProcAddress", "Ptr", uxtheme, "Ptr", 135, "Ptr")
		FlushMenuThemes     := DllCall("kernel32\GetProcAddress", "Ptr", uxtheme, "Ptr", 136, "Ptr")
		switch DarkMode
		{
			case True:
			{
				DllCall("dwmapi\DwmSetWindowAttribute", "Ptr", GuiObj.hWnd, "Int", DWMWA_USE_IMMERSIVE_DARK_MODE, "Int*", True, "Int", 4)
				DllCall(SetPreferredAppMode, "Int", PreferredAppMode["ForceDark"])
				DllCall(FlushMenuThemes)
				GuiObj.BackColor := DarkColors["Background"]
			}
			default:
			{
				DllCall("dwmapi\DwmSetWindowAttribute", "Ptr", GuiObj.hWnd, "Int", DWMWA_USE_IMMERSIVE_DARK_MODE, "Int*", False, "Int", 4)
				DllCall(SetPreferredAppMode, "Int", PreferredAppMode["Default"])
				DllCall(FlushMenuThemes)
				GuiObj.BackColor := "Default"
			}
		}
	}
}


SetWindowTheme(GuiObj, DarkMode := True)
{
	static GWL_WNDPROC        := -4
	static GWL_STYLE          := -16
	static ES_MULTILINE       := 0x0004
	static LVM_GETTEXTCOLOR   := 0x1023
	static LVM_SETTEXTCOLOR   := 0x1024
	static LVM_GETTEXTBKCOLOR := 0x1025
	static LVM_SETTEXTBKCOLOR := 0x1026
	static LVM_GETBKCOLOR     := 0x1000
	static LVM_SETBKCOLOR     := 0x1001
	static LVM_GETHEADER      := 0x101F
	static GetWindowLong      := A_PtrSize = 8 ? "GetWindowLongPtr" : "GetWindowLong"
	static SetWindowLong      := A_PtrSize = 8 ? "SetWindowLongPtr" : "SetWindowLong"
	static Init               := False
	static LV_Init            := False
	global IsDarkMode         := DarkMode

	Mode_Explorer  := (DarkMode ? "DarkMode_Explorer"  : "Explorer" )
	Mode_CFD       := (DarkMode ? "DarkMode_CFD"       : "CFD"      )
	Mode_ItemsView := (DarkMode ? "DarkMode_ItemsView" : "ItemsView")

	for hWnd, GuiCtrlObj in GuiObj
	{
		switch GuiCtrlObj.Type
		{
			case "Button", "CheckBox", "ListBox", "UpDown":
			{
				DllCall("uxtheme\SetWindowTheme", "Ptr", GuiCtrlObj.hWnd, "Str", Mode_Explorer, "Ptr", 0)
			}
			case "ComboBox", "DDL":
			{
				DllCall("uxtheme\SetWindowTheme", "Ptr", GuiCtrlObj.hWnd, "Str", Mode_CFD, "Ptr", 0)
			}
			case "Edit":
			{
				if (DllCall("user32\" GetWindowLong, "Ptr", GuiCtrlObj.hWnd, "Int", GWL_STYLE) & ES_MULTILINE)
				{
					DllCall("uxtheme\SetWindowTheme", "Ptr", GuiCtrlObj.hWnd, "Str", Mode_Explorer, "Ptr", 0)
				}
				else
				{
					DllCall("uxtheme\SetWindowTheme", "Ptr", GuiCtrlObj.hWnd, "Str", Mode_CFD, "Ptr", 0)
				}
			}
			case "ListView":
			{
				if !(LV_Init)
				{
					static LV_TEXTCOLOR   := SendMessage(LVM_GETTEXTCOLOR,   0, 0, GuiCtrlObj.hWnd)
					static LV_TEXTBKCOLOR := SendMessage(LVM_GETTEXTBKCOLOR, 0, 0, GuiCtrlObj.hWnd)
					static LV_BKCOLOR     := SendMessage(LVM_GETBKCOLOR,     0, 0, GuiCtrlObj.hWnd)
					LV_Init := True
				}
				GuiCtrlObj.Opt("-Redraw")
				switch DarkMode
				{
					case True:
					{
						SendMessage(LVM_SETTEXTCOLOR,   0, DarkColors["Font"],       GuiCtrlObj.hWnd)
						SendMessage(LVM_SETTEXTBKCOLOR, 0, DarkColors["Background"], GuiCtrlObj.hWnd)
						SendMessage(LVM_SETBKCOLOR,     0, DarkColors["Background"], GuiCtrlObj.hWnd)
					}
					default:
					{
						SendMessage(LVM_SETTEXTCOLOR,   0, LV_TEXTCOLOR,   GuiCtrlObj.hWnd)
						SendMessage(LVM_SETTEXTBKCOLOR, 0, LV_TEXTBKCOLOR, GuiCtrlObj.hWnd)
						SendMessage(LVM_SETBKCOLOR,     0, LV_BKCOLOR,     GuiCtrlObj.hWnd)
					}
				}
				DllCall("uxtheme\SetWindowTheme", "Ptr", GuiCtrlObj.hWnd, "Str", Mode_Explorer, "Ptr", 0)
				
				; To color the selection - scrollbar turns back to normal
				;DllCall("uxtheme\SetWindowTheme", "Ptr", GuiCtrlObj.hWnd, "Str", Mode_ItemsView, "Ptr", 0)

				; Header Text needs some NM_CUSTOMDRAW coloring
				LV_Header := SendMessage(LVM_GETHEADER, 0, 0, GuiCtrlObj.hWnd)
				DllCall("uxtheme\SetWindowTheme", "Ptr", LV_Header, "Str", Mode_ItemsView, "Ptr", 0)
				GuiCtrlObj.Opt("+Redraw")
			}
		}
	}

	if !(Init)
	{
		; https://www.autohotkey.com/docs/v2/lib/CallbackCreate.htm#ExSubclassGUI
		global WindowProcNew := CallbackCreate(WindowProc)  ; Avoid fast-mode for subclassing.
		global WindowProcOld := DllCall("user32\" SetWindowLong, "Ptr", GuiObj.Hwnd, "Int", GWL_WNDPROC, "Ptr", WindowProcNew, "Ptr")
		Init := True
	}
}



WindowProc(hwnd, uMsg, wParam, lParam)
{
	critical
	static WM_CTLCOLOREDIT    := 0x0133
	static WM_CTLCOLORLISTBOX := 0x0134
	static WM_CTLCOLORBTN     := 0x0135
	static WM_CTLCOLORSTATIC  := 0x0138
	static DC_BRUSH           := 18

	if (IsDarkMode)
	{
		switch uMsg
		{
			case WM_CTLCOLOREDIT, WM_CTLCOLORLISTBOX:
			{
				DllCall("gdi32\SetTextColor", "Ptr", wParam, "UInt", DarkColors["Font"])
				DllCall("gdi32\SetBkColor", "Ptr", wParam, "UInt", DarkColors["Controls"])
				DllCall("gdi32\SetDCBrushColor", "Ptr", wParam, "UInt", DarkColors["Controls"], "UInt")
				return DllCall("gdi32\GetStockObject", "Int", DC_BRUSH, "Ptr")
			}
			case WM_CTLCOLORBTN:
			{
				DllCall("gdi32\SetDCBrushColor", "Ptr", wParam, "UInt", DarkColors["Background"], "UInt")
				return DllCall("gdi32\GetStockObject", "Int", DC_BRUSH, "Ptr")
			}
			case WM_CTLCOLORSTATIC:
			{
				DllCall("gdi32\SetTextColor", "Ptr", wParam, "UInt", DarkColors["Font"])
				DllCall("gdi32\SetBkColor", "Ptr", wParam, "UInt", DarkColors["Background"])
				return TextBackgroundBrush
			}
		}
	}
	return DllCall("user32\CallWindowProc", "Ptr", WindowProcOld, "Ptr", hwnd, "UInt", uMsg, "Ptr", wParam, "Ptr", lParam)
}


; https://www.autohotkey.com/boards/viewtopic.php?t=72520
class ADS
{
	static Save(mode, stream := "sfdata")
	{
		IniWrite(mode, A_ScriptFullPath ":" stream, "section", mode)
		return
	}

	static Load(mode, stream := "sfdata")
	{
		mode := IniRead(A_ScriptFullPath ":" stream, "section", mode, "")
		return mode
	}

	static Reset(stream := "sfdata")
	{
		FileDelete(A_ScriptFullPath ":" stream)
		return
	}
}
Ref:
viewtopic.php?t=72520 (by haichen)
[AHK] v2.0.5 | [WIN] 11 Pro (Version 22H2) | [GitHub] Profile
AHK_user
Posts: 515
Joined: 04 Dec 2015, 14:52
Location: Belgium

Re: DarkMode (Force or Toggle)

09 Apr 2023, 13:30

To be complete:

- You can use the option -E0200 for edit controls to remove the white border
- This is the code to change the Menu to dark mode:

Code: Select all

	uxtheme := DllCall("GetModuleHandle", "str", "uxtheme", "ptr")
	SetPreferredAppMode := DllCall("GetProcAddress", "ptr", uxtheme, "ptr", 135, "ptr")
	FlushMenuThemes := DllCall("GetProcAddress", "ptr", uxtheme, "ptr", 136, "ptr")
	DllCall(SetPreferredAppMode, "int", 1)	; Dark
	DllCall(FlushMenuThemes)
User avatar
jNizM
Posts: 3183
Joined: 30 Sep 2013, 01:33
Contact:

Re: DarkMode (Force or Toggle)

11 Apr 2023, 01:44

Menu was already implemented. But thanks anyway
[AHK] v2.0.5 | [WIN] 11 Pro (Version 22H2) | [GitHub] Profile
jsong55
Posts: 253
Joined: 30 Mar 2021, 22:02

Re: DarkMode (Force or Toggle)

13 Apr 2023, 20:26

Can I make some suggestions so we can implement it more widely and with greater flexibility?

Where we can do something like that

Code: Select all

ColorScheme:=Map("LightGreen","41644A","DarkGreen","263A29","Rose","D21312","FunPink","E8A0BF")
SelectedColors:=Map("BG",ColorScheme[DarkGreen],"FontColor",ColorScheme[FunPink])
G:=Gui()
G.Add("Edit"," vEdit1","Some Value Here")
G["Edit1"].SetColors(SelectedColors)
Write into a class so easier to use.

Maybe SetColors Extends Gui
User avatar
TheArkive
Posts: 1028
Joined: 05 Aug 2016, 08:06
Location: The Construct
Contact:

Re: DarkMode (Force or Toggle)

14 Apr 2023, 03:37

This looks really cool.

I've been messing around with OwnerDrawn and NVCUSTOMDRAW stuff. I've had a lot of success so far, but I'm really getting stumped with certain parts of certain controls.

This takes care of most of the "big stuff". Nicely done. I'll try this out and see if I can add/suggest anything.

The NppDarkColors links is very informative. Thanks.
robodesign
Posts: 934
Joined: 30 Sep 2017, 03:59
Location: Romania
Contact:

Re: DarkMode (Force or Toggle)

06 May 2023, 05:14

Does this work on win11 ? I had issues on a system with win11 - the menus were not dark...
-------------------------
KeyPress OSD v4: GitHub or forum. (presentation video)
Quick Picto Viewer: GitHub or forum.
AHK GDI+ expanded / compilation library (on GitHub)
My home page.
sashaatx
Posts: 342
Joined: 27 May 2021, 08:27
Contact:

Re: DarkMode (Force or Toggle)

28 Nov 2023, 11:03

jNizM wrote:
09 Apr 2023, 06:38
@jNizM

edit: issue is with winsettrans not dark mode.

I'm having issues with Tabs, getting a desktop flickering on switching tabs

Code: Select all

    global gui__


    gui__ := Gui(, "Test - List"), gui__.Opt("+Resize +MinSize550x350 -DPIScale")
    gui__.SetFont("s37 cWhite")


    gui__.Tabs := gui__.Add("Tab3", "Background19212f x50 y50 w500 h500", ["Order Details", "Second Tab", "Second Tab"])
    gui__.Tabs.SetFont("s12")
        
    gui__.Tabs.UseTab(3)
    ;gui__.GroupBox
    gui__.LB_Orders := gui__.Add("ListBox", "Background162235 x52 y55 w490 h490", [])
    gui__.LB_Orders.SetFont("s16")
    gui__.Tabs.UseTab()

    gui__.backcolor := "121d30"
    SetWindowAttribute(gui__)
    SetWindowTheme(gui__)



    gui__.Show("h" 800 " w" 1500)
    gui__.Maximize()
    WinSetTransparent 240, "ahk_id " gui__.hwnd

SetWindowAttribute(GuiObj, DarkMode := True)
{
    global DarkColors          := Map("Background", "0x202020", "Controls", "0x404040", "Font", "0xE0E0E0")
    global TextBackgroundBrush := DllCall("gdi32\CreateSolidBrush", "UInt", DarkColors["Background"], "Ptr")
    static PreferredAppMode    := Map("Default", 0, "AllowDark", 1, "ForceDark", 2, "ForceLight", 3, "Max", 4)

    if (VerCompare(A_OSVersion, "10.0.17763") >= 0)
    {
        DWMWA_USE_IMMERSIVE_DARK_MODE := 19
        if (VerCompare(A_OSVersion, "10.0.18985") >= 0)
        {
            DWMWA_USE_IMMERSIVE_DARK_MODE := 20
        }
        uxtheme := DllCall("kernel32\GetModuleHandle", "Str", "uxtheme", "Ptr")
        SetPreferredAppMode := DllCall("kernel32\GetProcAddress", "Ptr", uxtheme, "Ptr", 135, "Ptr")
        FlushMenuThemes     := DllCall("kernel32\GetProcAddress", "Ptr", uxtheme, "Ptr", 136, "Ptr")
        switch DarkMode
        {
            case True:
            {
                DllCall("dwmapi\DwmSetWindowAttribute", "Ptr", GuiObj.hWnd, "Int", DWMWA_USE_IMMERSIVE_DARK_MODE, "Int*", True, "Int", 4)
                DllCall(SetPreferredAppMode, "Int", PreferredAppMode["ForceDark"])
                DllCall(FlushMenuThemes)
                GuiObj.BackColor := DarkColors["Background"]
            }
            default:
            {
                DllCall("dwmapi\DwmSetWindowAttribute", "Ptr", GuiObj.hWnd, "Int", DWMWA_USE_IMMERSIVE_DARK_MODE, "Int*", False, "Int", 4)
                DllCall(SetPreferredAppMode, "Int", PreferredAppMode["Default"])
                DllCall(FlushMenuThemes)
                GuiObj.BackColor := "Default"
            }
        }
    }
}


SetWindowTheme(GuiObj, DarkMode := True)
{
    static GWL_WNDPROC        := -4
    static GWL_STYLE          := -16
    static ES_MULTILINE       := 0x0004
    static LVM_GETTEXTCOLOR   := 0x1023
    static LVM_SETTEXTCOLOR   := 0x1024
    static LVM_GETTEXTBKCOLOR := 0x1025
    static LVM_SETTEXTBKCOLOR := 0x1026
    static LVM_GETBKCOLOR     := 0x1000
    static LVM_SETBKCOLOR     := 0x1001
    static LVM_GETHEADER      := 0x101F
    static GetWindowLong      := A_PtrSize = 8 ? "GetWindowLongPtr" : "GetWindowLong"
    static SetWindowLong      := A_PtrSize = 8 ? "SetWindowLongPtr" : "SetWindowLong"
    static Init               := False
    static LV_Init            := False
    global IsDarkMode         := DarkMode

    Mode_Explorer  := (DarkMode ? "DarkMode_Explorer"  : "Explorer" )
    Mode_CFD       := (DarkMode ? "DarkMode_CFD"       : "CFD"      )
    Mode_ItemsView := (DarkMode ? "DarkMode_ItemsView" : "ItemsView")

    for hWnd, GuiCtrlObj in GuiObj
    {
        switch GuiCtrlObj.Type
        {
            case "Button", "CheckBox", "ListBox", "UpDown":
            {
                DllCall("uxtheme\SetWindowTheme", "Ptr", GuiCtrlObj.hWnd, "Str", Mode_Explorer, "Ptr", 0)
            }
            case "ComboBox", "DDL":
            {
                DllCall("uxtheme\SetWindowTheme", "Ptr", GuiCtrlObj.hWnd, "Str", Mode_CFD, "Ptr", 0)
            }
            case "Edit":
            {
                if (DllCall("user32\" GetWindowLong, "Ptr", GuiCtrlObj.hWnd, "Int", GWL_STYLE) & ES_MULTILINE)
                {
                    DllCall("uxtheme\SetWindowTheme", "Ptr", GuiCtrlObj.hWnd, "Str", Mode_Explorer, "Ptr", 0)
                }
                else
                {
                    DllCall("uxtheme\SetWindowTheme", "Ptr", GuiCtrlObj.hWnd, "Str", Mode_CFD, "Ptr", 0)
                }
            }
            case "ListView":
            {
                if !(LV_Init)
                {
                    static LV_TEXTCOLOR   := SendMessage(LVM_GETTEXTCOLOR,   0, 0, GuiCtrlObj.hWnd)
                    static LV_TEXTBKCOLOR := SendMessage(LVM_GETTEXTBKCOLOR, 0, 0, GuiCtrlObj.hWnd)
                    static LV_BKCOLOR     := SendMessage(LVM_GETBKCOLOR,     0, 0, GuiCtrlObj.hWnd)
                    LV_Init := True
                }
                GuiCtrlObj.Opt("-Redraw")
                switch DarkMode
                {
                    case True:
                    {
                        SendMessage(LVM_SETTEXTCOLOR,   0, DarkColors["Font"],       GuiCtrlObj.hWnd)
                        SendMessage(LVM_SETTEXTBKCOLOR, 0, DarkColors["Background"], GuiCtrlObj.hWnd)
                        SendMessage(LVM_SETBKCOLOR,     0, DarkColors["Background"], GuiCtrlObj.hWnd)
                    }
                    default:
                    {
                        SendMessage(LVM_SETTEXTCOLOR,   0, LV_TEXTCOLOR,   GuiCtrlObj.hWnd)
                        SendMessage(LVM_SETTEXTBKCOLOR, 0, LV_TEXTBKCOLOR, GuiCtrlObj.hWnd)
                        SendMessage(LVM_SETBKCOLOR,     0, LV_BKCOLOR,     GuiCtrlObj.hWnd)
                    }
                }
                DllCall("uxtheme\SetWindowTheme", "Ptr", GuiCtrlObj.hWnd, "Str", Mode_Explorer, "Ptr", 0)
                
                ; To color the selection - scrollbar turns back to normal
                ;DllCall("uxtheme\SetWindowTheme", "Ptr", GuiCtrlObj.hWnd, "Str", Mode_ItemsView, "Ptr", 0)

                ; Header Text needs some NM_CUSTOMDRAW coloring
                LV_Header := SendMessage(LVM_GETHEADER, 0, 0, GuiCtrlObj.hWnd)
                DllCall("uxtheme\SetWindowTheme", "Ptr", LV_Header, "Str", Mode_ItemsView, "Ptr", 0)
                GuiCtrlObj.Opt("+Redraw")
            }
        }
    }

    if !(Init)
    {
        ; https://www.autohotkey.com/docs/v2/lib/CallbackCreate.htm#ExSubclassGUI
        global WindowProcNew := CallbackCreate(WindowProc)  ; Avoid fast-mode for subclassing.
        global WindowProcOld := DllCall("user32\" SetWindowLong, "Ptr", GuiObj.Hwnd, "Int", GWL_WNDPROC, "Ptr", WindowProcNew, "Ptr")
        Init := True
    }
}



WindowProc(hwnd, uMsg, wParam, lParam)
{
    critical
    static WM_CTLCOLOREDIT    := 0x0133
    static WM_CTLCOLORLISTBOX := 0x0134
    static WM_CTLCOLORBTN     := 0x0135
    static WM_CTLCOLORSTATIC  := 0x0138
    static DC_BRUSH           := 18

    if (IsDarkMode)
    {
        switch uMsg
        {
            case WM_CTLCOLOREDIT, WM_CTLCOLORLISTBOX:
            {
                DllCall("gdi32\SetTextColor", "Ptr", wParam, "UInt", DarkColors["Font"])
                DllCall("gdi32\SetBkColor", "Ptr", wParam, "UInt", DarkColors["Controls"])
                DllCall("gdi32\SetDCBrushColor", "Ptr", wParam, "UInt", DarkColors["Controls"], "UInt")
                return DllCall("gdi32\GetStockObject", "Int", DC_BRUSH, "Ptr")
            }
            case WM_CTLCOLORBTN:
            {
                DllCall("gdi32\SetDCBrushColor", "Ptr", wParam, "UInt", DarkColors["Background"], "UInt")
                return DllCall("gdi32\GetStockObject", "Int", DC_BRUSH, "Ptr")
            }
            case WM_CTLCOLORSTATIC:
            {
                DllCall("gdi32\SetTextColor", "Ptr", wParam, "UInt", DarkColors["Font"])
                DllCall("gdi32\SetBkColor", "Ptr", wParam, "UInt", DarkColors["Background"])
                return TextBackgroundBrush
            }
        }
    }
    return DllCall("user32\CallWindowProc", "Ptr", WindowProcOld, "Ptr", hwnd, "UInt", uMsg, "Ptr", wParam, "Ptr", lParam)
}

    blackGuiCtrl(params*)
    {
        for ctrl in params
        {
            ctrl.Opt("Background000000")
        }
    }

https://github.com/samfisherirl
? /Easy-Auto-GUI-for-AHK-v2 ? /Useful-AHK-v2-Libraries-and-Classes : /Pulovers-Macro-Creator-for-AHKv2 :

Return to “Tips and Tricks”

Who is online

Users browsing this forum: No registered users and 3 guests