mirror of
https://github.com/EDCD/EDMarketConnector.git
synced 2025-06-20 16:54:31 +03:00
Merge pull request #1742 from EDCD/enhancement/theme/use-constants-not-magic-numbers
themes: Use defined constants for which theme throughout
This commit is contained in:
commit
a0887f1410
@ -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)
|
||||||
|
15
prefs.py
15
prefs.py
@ -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
|
||||||
|
129
theme.py
129
theme.py
@ -133,14 +133,14 @@ class _Theme(object):
|
|||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
self.active = None # Starts out with no theme
|
self.active = None # Starts out with no theme
|
||||||
self.minwidth: Optional[int] = None
|
self.minwidth: Optional[int] = None
|
||||||
self.widgets: Dict[tk.Widget, Set] = {}
|
self.widgets: Dict[tk.Widget | tk.BitmapImage, Set] = {}
|
||||||
self.widgets_pair: List = []
|
self.widgets_pair: List = []
|
||||||
self.defaults: Dict = {}
|
self.defaults: Dict = {}
|
||||||
self.current: Dict = {}
|
self.current: Dict = {}
|
||||||
self.default_ui_scale = None # None == not yet known
|
self.default_ui_scale = None # None == not yet known
|
||||||
self.startup_ui_scale = None
|
self.startup_ui_scale = None
|
||||||
|
|
||||||
def register(self, widget: tk.Widget) -> None: # noqa: CCR001, C901
|
def register(self, widget: tk.Widget | tk.BitmapImage) -> None: # noqa: CCR001, C901
|
||||||
# Note widget and children for later application of a theme. Note if
|
# Note widget and children for later application of a theme. Note if
|
||||||
# the widget has explicit fg or bg attributes.
|
# the widget has explicit fg or bg attributes.
|
||||||
assert isinstance(widget, tk.Widget) or isinstance(widget, tk.BitmapImage), widget
|
assert isinstance(widget, tk.Widget) or isinstance(widget, tk.BitmapImage), widget
|
||||||
@ -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()
|
||||||
@ -306,9 +310,19 @@ class _Theme(object):
|
|||||||
self._update_widget(child)
|
self._update_widget(child)
|
||||||
|
|
||||||
# Apply current theme to a single widget
|
# Apply current theme to a single widget
|
||||||
def _update_widget(self, widget: tk.Widget) -> None: # noqa: CCR001, C901
|
def _update_widget(self, widget: tk.Widget | tk.BitmapImage) -> None: # noqa: CCR001, C901
|
||||||
if widget not in self.widgets:
|
if widget not in self.widgets:
|
||||||
assert_str = f'{widget.winfo_class()} {widget} "{"text" in widget.keys() and widget["text"]}"'
|
if isinstance(widget, tk.Widget):
|
||||||
|
w_class = widget.winfo_class()
|
||||||
|
w_keys: List[str] = widget.keys()
|
||||||
|
|
||||||
|
else:
|
||||||
|
# There is no tk.BitmapImage.winfo_class()
|
||||||
|
w_class = ''
|
||||||
|
# There is no tk.BitmapImage.keys()
|
||||||
|
w_keys = []
|
||||||
|
|
||||||
|
assert_str = f'{w_class} {widget} "{"text" in w_keys and widget["text"]}"'
|
||||||
raise AssertionError(assert_str)
|
raise AssertionError(assert_str)
|
||||||
|
|
||||||
attribs: Set = self.widgets.get(widget, set())
|
attribs: Set = self.widgets.get(widget, set())
|
||||||
@ -375,8 +389,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)
|
||||||
|
|
||||||
@ -390,27 +403,35 @@ class _Theme(object):
|
|||||||
# Switch menus
|
# Switch menus
|
||||||
for pair, gridopts in self.widgets_pair:
|
for pair, gridopts in self.widgets_pair:
|
||||||
for widget in pair:
|
for widget in pair:
|
||||||
widget.grid_remove()
|
if isinstance(widget, tk.Widget):
|
||||||
|
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 +447,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 +483,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
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user