1
0
mirror of https://github.com/EDCD/EDMarketConnector.git synced 2025-06-07 19:03:23 +03:00

themes: Use defined constants for which theme throughout

This has been relying on knowledge of the magic numbers for far too long.

As part of this, remove all the obfuscating "oh, default is 0, and we want
that or any other theme, so treat this like a boolean" nonsense.

Also, stop assuming that "> 1" is a synonym for "transparent theme".  Just
Do The Equality Check.
This commit is contained in:
Athanasius 2022-12-05 11:52:29 +00:00
parent 0f5f625cfd
commit 62e285b52e
No known key found for this signature in database
GPG Key ID: 772697E181BB2767
3 changed files with 87 additions and 45 deletions

View File

@ -1799,18 +1799,14 @@ class AppWindow(object):
def onenter(self, event=None) -> None: def onenter(self, event=None) -> None:
"""Handle when our window gains focus.""" """Handle when our window gains focus."""
# TODO: This assumes that 1) transparent is at least 2, 2) there are if config.get_int('theme') == theme.THEME_TRANSPARENT:
# no new themes added after that.
if config.get_int('theme') > 1:
self.w.attributes("-transparentcolor", '') self.w.attributes("-transparentcolor", '')
self.blank_menubar.grid_remove() self.blank_menubar.grid_remove()
self.theme_menubar.grid(row=0, columnspan=2, sticky=tk.NSEW) self.theme_menubar.grid(row=0, columnspan=2, sticky=tk.NSEW)
def onleave(self, event=None) -> None: def onleave(self, event=None) -> None:
"""Handle when our window loses focus.""" """Handle when our window loses focus."""
# TODO: This assumes that 1) transparent is at least 2, 2) there are if config.get_int('theme') == theme.THEME_TRANSPARENT and event.widget == self.w:
# no new themes added after that.
if config.get_int('theme') > 1 and event.widget == self.w:
self.w.attributes("-transparentcolor", 'grey4') self.w.attributes("-transparentcolor", 'grey4')
self.theme_menubar.grid_remove() self.theme_menubar.grid_remove()
self.blank_menubar.grid(row=0, columnspan=2, sticky=tk.NSEW) self.blank_menubar.grid(row=0, columnspan=2, sticky=tk.NSEW)
@ -1887,7 +1883,7 @@ sys.path: {sys.path}'''
) )
if args.reset_ui: if args.reset_ui:
config.set('theme', 0) # 'Default' theme uses ID 0 config.set('theme', theme.THEME_DEFAULT)
config.set('ui_transparency', 100) # 100 is completely opaque config.set('ui_transparency', 100) # 100 is completely opaque
config.delete('font', suppress=True) config.delete('font', suppress=True)
config.delete('font_size', suppress=True) config.delete('font_size', suppress=True)

View File

@ -308,6 +308,7 @@ class PreferencesDialog(tk.Toplevel):
button.bind("<Return>", lambda event: self.apply()) button.bind("<Return>", lambda event: self.apply())
self.protocol("WM_DELETE_WINDOW", self._destroy) self.protocol("WM_DELETE_WINDOW", self._destroy)
# FIXME: Why are these being called when *creating* the Settings window?
# Selectively disable buttons depending on output settings # Selectively disable buttons depending on output settings
self.cmdrchanged() self.cmdrchanged()
self.themevarchanged() self.themevarchanged()
@ -733,13 +734,14 @@ class PreferencesDialog(tk.Toplevel):
# Appearance theme and language setting # Appearance theme and language setting
nb.Radiobutton( nb.Radiobutton(
# LANG: Label for 'Default' theme radio button # LANG: Label for 'Default' theme radio button
appearance_frame, text=_('Default'), variable=self.theme, value=0, command=self.themevarchanged appearance_frame, text=_('Default'), variable=self.theme,
value=theme.THEME_DEFAULT, command=self.themevarchanged
).grid(columnspan=3, padx=self.BUTTONX, sticky=tk.W, row=row.get()) ).grid(columnspan=3, padx=self.BUTTONX, sticky=tk.W, row=row.get())
# Appearance theme setting # Appearance theme setting
nb.Radiobutton( nb.Radiobutton(
# LANG: Label for 'Dark' theme radio button # LANG: Label for 'Dark' theme radio button
appearance_frame, text=_('Dark'), variable=self.theme, value=1, command=self.themevarchanged appearance_frame, text=_('Dark'), variable=self.theme, value=theme.THEME_DARK, command=self.themevarchanged
).grid(columnspan=3, padx=self.BUTTONX, sticky=tk.W, row=row.get()) ).grid(columnspan=3, padx=self.BUTTONX, sticky=tk.W, row=row.get())
if sys.platform == 'win32': if sys.platform == 'win32':
@ -748,7 +750,7 @@ class PreferencesDialog(tk.Toplevel):
# LANG: Label for 'Transparent' theme radio button # LANG: Label for 'Transparent' theme radio button
text=_('Transparent'), # Appearance theme setting text=_('Transparent'), # Appearance theme setting
variable=self.theme, variable=self.theme,
value=2, value=theme.THEME_TRANSPARENT,
command=self.themevarchanged command=self.themevarchanged
).grid(columnspan=3, padx=self.BUTTONX, sticky=tk.W, row=row.get()) ).grid(columnspan=3, padx=self.BUTTONX, sticky=tk.W, row=row.get())
@ -1149,7 +1151,12 @@ class PreferencesDialog(tk.Toplevel):
"""Update theme examples.""" """Update theme examples."""
self.theme_button_0['foreground'], self.theme_button_1['foreground'] = self.theme_colors self.theme_button_0['foreground'], self.theme_button_1['foreground'] = self.theme_colors
state = tk.NORMAL if self.theme.get() else tk.DISABLED if self.theme.get() == theme.THEME_DEFAULT:
state = tk.DISABLED # type: ignore
else:
state = tk.NORMAL # type: ignore
self.theme_label_0['state'] = state self.theme_label_0['state'] = state
self.theme_label_1['state'] = state self.theme_label_1['state'] = state
self.theme_button_0['state'] = state self.theme_button_0['state'] = state

107
theme.py
View File

@ -259,24 +259,7 @@ class _Theme(object):
if not config.get_str('dark_highlight'): if not config.get_str('dark_highlight'):
config.set('dark_highlight', 'white') config.set('dark_highlight', 'white')
if theme: if theme == self.THEME_DEFAULT:
# Dark
(r, g, b) = root.winfo_rgb(config.get_str('dark_text'))
self.current = {
'background': 'grey4', # OSX inactive dark titlebar color
'foreground': config.get_str('dark_text'),
'activebackground': config.get_str('dark_text'),
'activeforeground': 'grey4',
'disabledforeground': f'#{int(r/384):02x}{int(g/384):02x}{int(b/384):02x}',
'highlight': config.get_str('dark_highlight'),
# Font only supports Latin 1 / Supplement / Extended, and a
# few General Punctuation and Mathematical Operators
# LANG: Label for commander name in main window
'font': (theme > 1 and not 0x250 < ord(_('Cmdr')[0]) < 0x3000 and
tk_font.Font(family='Euro Caps', size=10, weight=tk_font.NORMAL) or
'TkDefaultFont'),
}
else:
# (Mostly) system colors # (Mostly) system colors
style = ttk.Style() style = ttk.Style()
self.current = { self.current = {
@ -292,9 +275,30 @@ class _Theme(object):
'font': 'TkDefaultFont', 'font': 'TkDefaultFont',
} }
# Apply current theme to a widget and its children, and register it for future updates else: # Dark *or* Transparent
(r, g, b) = root.winfo_rgb(config.get_str('dark_text'))
self.current = {
'background': 'grey4', # OSX inactive dark titlebar color
'foreground': config.get_str('dark_text'),
'activebackground': config.get_str('dark_text'),
'activeforeground': 'grey4',
'disabledforeground': f'#{int(r/384):02x}{int(g/384):02x}{int(b/384):02x}',
'highlight': config.get_str('dark_highlight'),
# Font only supports Latin 1 / Supplement / Extended, and a
# few General Punctuation and Mathematical Operators
# LANG: Label for commander name in main window
'font': (theme > 1 and not 0x250 < ord(_('Cmdr')[0]) < 0x3000 and
tk_font.Font(family='Euro Caps', size=10, weight=tk_font.NORMAL) or
'TkDefaultFont'),
}
def update(self, widget: tk.Widget) -> None: def update(self, widget: tk.Widget) -> None:
"""
Apply current theme to a widget and its children.
Also, register it for future updates.
:param widget: Target widget.
"""
assert isinstance(widget, tk.Widget) or isinstance(widget, tk.BitmapImage), widget assert isinstance(widget, tk.Widget) or isinstance(widget, tk.BitmapImage), widget
if not self.current: if not self.current:
return # No need to call this for widgets created in plugin_app() return # No need to call this for widgets created in plugin_app()
@ -375,8 +379,7 @@ class _Theme(object):
# Apply configured theme # Apply configured theme
def apply(self, root: tk.Tk) -> None: # noqa: CCR001 def apply(self, root: tk.Tk) -> None: # noqa: CCR001, C901
theme = config.get_int('theme') theme = config.get_int('theme')
self._colors(root, theme) self._colors(root, theme)
@ -392,25 +395,31 @@ class _Theme(object):
for widget in pair: for widget in pair:
widget.grid_remove() widget.grid_remove()
if isinstance(pair[0], tk.Menu): if isinstance(pair[0], tk.Menu):
if theme: if theme == self.THEME_DEFAULT:
root['menu'] = pair[0]
else: # Dark *or* Transparent
root['menu'] = '' root['menu'] = ''
pair[theme].grid(**gridopts) pair[theme].grid(**gridopts)
else:
root['menu'] = pair[0]
else: else:
pair[theme].grid(**gridopts) pair[theme].grid(**gridopts)
if self.active == theme: if self.active == theme:
return # Don't need to mess with the window manager return # Don't need to mess with the window manager
else: else:
self.active = theme self.active = theme
if sys.platform == 'darwin': if sys.platform == 'darwin':
from AppKit import NSAppearance, NSApplication, NSMiniaturizableWindowMask, NSResizableWindowMask from AppKit import NSAppearance, NSApplication, NSMiniaturizableWindowMask, NSResizableWindowMask
root.update_idletasks() # need main window to be created root.update_idletasks() # need main window to be created
appearance = NSAppearance.appearanceNamed_(theme and if theme == self.THEME_DEFAULT:
'NSAppearanceNameDarkAqua' or appearance = NSAppearance.appearanceNamed_('NSAppearanceNameAqua')
'NSAppearanceNameAqua')
else: # Dark (Transparent only on win32)
appearance = NSAppearance.appearanceNamed_('NSAppearanceNameDarkAqua')
for window in NSApplication.sharedApplication().windows(): for window in NSApplication.sharedApplication().windows():
window.setStyleMask_(window.styleMask() & ~( window.setStyleMask_(window.styleMask() & ~(
NSMiniaturizableWindowMask | NSResizableWindowMask)) # disable zoom NSMiniaturizableWindowMask | NSResizableWindowMask)) # disable zoom
@ -426,14 +435,30 @@ class _Theme(object):
GetWindowLongW = ctypes.windll.user32.GetWindowLongW # noqa: N806 # ctypes GetWindowLongW = ctypes.windll.user32.GetWindowLongW # noqa: N806 # ctypes
SetWindowLongW = ctypes.windll.user32.SetWindowLongW # noqa: N806 # ctypes SetWindowLongW = ctypes.windll.user32.SetWindowLongW # noqa: N806 # ctypes
root.overrideredirect(theme and True or False) # FIXME: Lose the "treat this like a boolean" bullshit
root.attributes("-transparentcolor", theme > 1 and 'grey4' or '') if theme == self.THEME_DEFAULT:
root.overrideredirect(False)
else:
root.overrideredirect(True)
if theme == self.THEME_TRANSPARENT:
root.attributes("-transparentcolor", 'grey4')
else:
root.attributes("-transparentcolor", '')
root.withdraw() root.withdraw()
root.update_idletasks() # Size and windows styles get recalculated here root.update_idletasks() # Size and windows styles get recalculated here
hwnd = ctypes.windll.user32.GetParent(root.winfo_id()) hwnd = ctypes.windll.user32.GetParent(root.winfo_id())
SetWindowLongW(hwnd, GWL_STYLE, GetWindowLongW(hwnd, GWL_STYLE) & ~WS_MAXIMIZEBOX) # disable maximize SetWindowLongW(hwnd, GWL_STYLE, GetWindowLongW(hwnd, GWL_STYLE) & ~WS_MAXIMIZEBOX) # disable maximize
SetWindowLongW(hwnd, GWL_EXSTYLE, theme > 1 and WS_EX_APPWINDOW |
WS_EX_LAYERED or WS_EX_APPWINDOW) # Add to taskbar if theme == self.THEME_TRANSPARENT:
SetWindowLongW(hwnd, GWL_EXSTYLE, WS_EX_APPWINDOW | WS_EX_LAYERED) # Add to taskbar
else:
SetWindowLongW(hwnd, GWL_EXSTYLE, WS_EX_APPWINDOW) # Add to taskbar
root.deiconify() root.deiconify()
root.wait_visibility() # need main window to be displayed before returning root.wait_visibility() # need main window to be displayed before returning
@ -446,11 +471,25 @@ class _Theme(object):
children = Window() children = Window()
nchildren = c_uint() nchildren = c_uint()
XQueryTree(dpy, root.winfo_id(), byref(xroot), byref(parent), byref(children), byref(nchildren)) XQueryTree(dpy, root.winfo_id(), byref(xroot), byref(parent), byref(children), byref(nchildren))
XChangeProperty(dpy, parent, motif_wm_hints_property, motif_wm_hints_property, 32, if theme == self.THEME_DEFAULT:
PropModeReplace, theme and motif_wm_hints_dark or motif_wm_hints_normal, 5) wm_hints = motif_wm_hints_normal
else: # Dark *or* Transparent
wm_hints = motif_wm_hints_dark
XChangeProperty(
dpy, parent, motif_wm_hints_property, motif_wm_hints_property, 32, PropModeReplace, wm_hints, 5
)
XFlush(dpy) XFlush(dpy)
else: else:
root.overrideredirect(theme and 1 or 0) if theme == self.THEME_DEFAULT:
root.overrideredirect(False)
else: # Dark *or* Transparent
root.overrideredirect(True)
root.deiconify() root.deiconify()
root.wait_visibility() # need main window to be displayed before returning root.wait_visibility() # need main window to be displayed before returning