Skip to content

Commit ffb5459

Browse files
yveslltejlmand
authored andcommitted
guiconfig: Add dark mode
TK under Windows/Linux did not have a native support for dark mode. Signed-off-by: Yves Wang <[email protected]>
1 parent 601f63d commit ffb5459

File tree

1 file changed

+126
-6
lines changed

1 file changed

+126
-6
lines changed

guiconfig.py

Lines changed: 126 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,47 @@ def _needs_save():
271271
# No need to prompt for save
272272
return False
273273

274+
def _detect_system_dark_mode():
275+
if sys.platform == "win32":
276+
try:
277+
import winreg
278+
registry = winreg.ConnectRegistry(None, winreg.HKEY_CURRENT_USER)
279+
key = winreg.OpenKey(registry,
280+
r"Software\Microsoft\Windows\CurrentVersion\Themes\Personalize")
281+
value, _ = winreg.QueryValueEx(key, "AppsUseLightTheme")
282+
winreg.CloseKey(key)
283+
return value == 0
284+
except (ImportError, OSError, WindowsError) as _:
285+
return False
286+
287+
elif sys.platform.startswith("linux"):
288+
if os.getenv('GTK_THEME', '').lower().find('dark') != -1:
289+
return True
290+
291+
import subprocess
292+
try:
293+
result = subprocess.run(
294+
["gsettings", "get", "org.gnome.desktop.interface", "gtk-theme"],
295+
capture_output=True, text=True
296+
)
297+
if "dark" in result.stdout.lower():
298+
return True
299+
except (subprocess.SubprocessError, OSError) as _:
300+
pass
301+
302+
try:
303+
result = subprocess.run(
304+
["kreadconfig5", "--group", "General", "--key", "ColorScheme"],
305+
capture_output=True, text=True
306+
)
307+
if "dark" in result.stdout.lower():
308+
return True
309+
except (subprocess.SubprocessError, OSError) as _:
310+
return False
311+
312+
# TK 8.6.9+ supports dark mode natively on macOS
313+
return False
314+
274315

275316
def _create_id_to_node():
276317
global _id_to_node
@@ -393,6 +434,8 @@ def _fix_treeview_issues():
393434

394435
def _init_misc_ui():
395436
# Does misc. UI initialization, like setting the title, icon, and theme
437+
global _dark_mode
438+
_dark_mode = _detect_system_dark_mode()
396439

397440
_root.title(_kconf.mainmenu_text)
398441
# iconphoto() isn't available in Python 2's Tkinter
@@ -404,10 +447,69 @@ def _init_misc_ui():
404447

405448
# Use the 'clam' theme on *nix if it's available. It looks nicer than the
406449
# 'default' theme.
407-
if _root.tk.call("tk", "windowingsystem") == "x11":
450+
if _dark_mode:
408451
style = ttk.Style()
409-
if "clam" in style.theme_names():
410-
style.theme_use("clam")
452+
_root.configure(bg='#2b2b2b')
453+
454+
style.theme_use('clam')
455+
456+
style.configure(".",
457+
background='#2b2b2b',
458+
foreground='#ffffff',
459+
fieldbackground='#3c3c3c',
460+
bordercolor='#404040',
461+
darkcolor='#222222',
462+
lightcolor='#404040',
463+
selectbackground='#5a5a5a',
464+
selectforeground='#ffffff')
465+
466+
style.configure("Treeview",
467+
background='#3c3c3c',
468+
foreground='#ffffff',
469+
fieldbackground='#3c3c3c')
470+
style.configure("Treeview.Heading",
471+
background='#404040',
472+
foreground='#ffffff')
473+
style.map("Treeview.Heading",
474+
background=[('active', '#5a5a5a')],
475+
foreground=[('active', '#ffffff')])
476+
style.map('Treeview',
477+
background=[('selected', '#5a5a5a')],
478+
foreground=[('selected', '#ffffff')])
479+
480+
style.configure("TButton",
481+
background='#404040',
482+
foreground='#ffffff',)
483+
style.map("TButton",
484+
background=[('active', '#5a5a5a')])
485+
486+
style.configure("TEntry",
487+
fieldbackground='#3c3c3c',
488+
foreground='#ffffff',
489+
insertcolor='#ffffff')
490+
491+
style.configure("TLabel",
492+
background='#2b2b2b',
493+
foreground='#ffffff')
494+
495+
style.configure("TFrame",
496+
background='#2b2b2b')
497+
498+
style.configure("TCheckbutton",
499+
background='#2b2b2b',
500+
foreground='#ffffff',
501+
focuscolor='none')
502+
style.map("TCheckbutton",
503+
background=[('active', '#3c3c3c')],
504+
foreground=[('active', '#ffffff')])
505+
506+
style.configure("TPanedwindow",
507+
background='#2b2b2b')
508+
else:
509+
if _root.tk.call("tk", "windowingsystem") == "x11":
510+
style = ttk.Style()
511+
if "clam" in style.theme_names():
512+
style.theme_use("clam")
411513

412514

413515
def _create_top_widgets():
@@ -584,12 +686,22 @@ def _create_kconfig_desc(parent):
584686

585687
frame = ttk.Frame(parent)
586688

587-
desc = Text(frame, height=12, wrap="none", borderwidth=0,
588-
state="disabled")
589-
desc.grid(column=0, row=0, sticky="nsew")
689+
if _dark_mode:
690+
desc = Text(frame, height=12, wrap="word", borderwidth=0,
691+
state="disabled",
692+
bg='#3c3c3c',
693+
fg='#ffffff',
694+
insertbackground='#ffffff',
695+
selectbackground='#5a5a5a',
696+
selectforeground='#ffffff',
697+
relief='flat')
698+
else:
699+
desc = Text(frame, height=12, wrap="word", borderwidth=0,
700+
state="disabled")
590701

591702
# Work around not being to Ctrl-C/V text from a disabled Text widget, with a
592703
# tip found in https://stackoverflow.com/questions/3842155/is-there-a-way-to-make-the-tkinter-text-widget-read-only
704+
desc.grid(column=0, row=0, sticky="nsew")
593705
desc.bind("<1>", lambda _: desc.focus_set())
594706

595707
_add_vscrollbar(frame, desc)
@@ -1194,6 +1306,10 @@ def cancel(_=None):
11941306
sym = node.item
11951307

11961308
dialog = Toplevel(parent)
1309+
1310+
if _dark_mode:
1311+
dialog.configure(bg='#2b2b2b')
1312+
11971313
dialog.title("Enter {} value".format(TYPE_TO_STR[sym.type]))
11981314
dialog.resizable(False, False)
11991315
dialog.transient(parent)
@@ -1780,6 +1896,10 @@ def tree_select(_):
17801896

17811897

17821898
dialog = Toplevel(_root)
1899+
1900+
if _dark_mode:
1901+
dialog.configure(bg='#2b2b2b')
1902+
17831903
dialog.geometry("+{}+{}".format(
17841904
_root.winfo_rootx() + 50, _root.winfo_rooty() + 50))
17851905
dialog.title("Jump to symbol/choice/menu/comment")

0 commit comments

Comments
 (0)