diff --git a/EDMarketConnector.py b/EDMarketConnector.py index 60e9f546..74ce8ace 100755 --- a/EDMarketConnector.py +++ b/EDMarketConnector.py @@ -1799,18 +1799,14 @@ class AppWindow(object): def onenter(self, event=None) -> None: """Handle when our window gains focus.""" - # TODO: This assumes that 1) transparent is at least 2, 2) there are - # no new themes added after that. - if config.get_int('theme') > 1: + if config.get_int('theme') == theme.THEME_TRANSPARENT: self.w.attributes("-transparentcolor", '') self.blank_menubar.grid_remove() self.theme_menubar.grid(row=0, columnspan=2, sticky=tk.NSEW) def onleave(self, event=None) -> None: """Handle when our window loses focus.""" - # TODO: This assumes that 1) transparent is at least 2, 2) there are - # no new themes added after that. - if config.get_int('theme') > 1 and event.widget == self.w: + if config.get_int('theme') == theme.THEME_TRANSPARENT and event.widget == self.w: self.w.attributes("-transparentcolor", 'grey4') self.theme_menubar.grid_remove() self.blank_menubar.grid(row=0, columnspan=2, sticky=tk.NSEW) @@ -1887,7 +1883,7 @@ sys.path: {sys.path}''' ) 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.delete('font', suppress=True) config.delete('font_size', suppress=True) diff --git a/prefs.py b/prefs.py index 376b6c67..985ef581 100644 --- a/prefs.py +++ b/prefs.py @@ -308,6 +308,7 @@ class PreferencesDialog(tk.Toplevel): button.bind("", lambda event: self.apply()) 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 self.cmdrchanged() self.themevarchanged() @@ -733,13 +734,14 @@ class PreferencesDialog(tk.Toplevel): # Appearance theme and language setting nb.Radiobutton( # 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()) # Appearance theme setting nb.Radiobutton( # 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()) if sys.platform == 'win32': @@ -748,7 +750,7 @@ class PreferencesDialog(tk.Toplevel): # LANG: Label for 'Transparent' theme radio button text=_('Transparent'), # Appearance theme setting variable=self.theme, - value=2, + value=theme.THEME_TRANSPARENT, command=self.themevarchanged ).grid(columnspan=3, padx=self.BUTTONX, sticky=tk.W, row=row.get()) @@ -1149,7 +1151,12 @@ class PreferencesDialog(tk.Toplevel): """Update theme examples.""" 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_1['state'] = state self.theme_button_0['state'] = state diff --git a/theme.py b/theme.py index 2707ad42..503f2dc0 100644 --- a/theme.py +++ b/theme.py @@ -259,24 +259,7 @@ class _Theme(object): if not config.get_str('dark_highlight'): config.set('dark_highlight', 'white') - if theme: - # 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: + if theme == self.THEME_DEFAULT: # (Mostly) system colors style = ttk.Style() self.current = { @@ -292,9 +275,30 @@ class _Theme(object): '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: + """ + 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 if not self.current: return # No need to call this for widgets created in plugin_app() @@ -375,8 +379,7 @@ class _Theme(object): # 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') self._colors(root, theme) @@ -392,25 +395,31 @@ class _Theme(object): for widget in pair: widget.grid_remove() if isinstance(pair[0], tk.Menu): - if theme: + if theme == self.THEME_DEFAULT: + root['menu'] = pair[0] + + else: # Dark *or* Transparent root['menu'] = '' pair[theme].grid(**gridopts) - else: - root['menu'] = pair[0] + else: pair[theme].grid(**gridopts) if self.active == theme: return # Don't need to mess with the window manager + else: self.active = theme if sys.platform == 'darwin': from AppKit import NSAppearance, NSApplication, NSMiniaturizableWindowMask, NSResizableWindowMask root.update_idletasks() # need main window to be created - appearance = NSAppearance.appearanceNamed_(theme and - 'NSAppearanceNameDarkAqua' or - 'NSAppearanceNameAqua') + if theme == self.THEME_DEFAULT: + appearance = NSAppearance.appearanceNamed_('NSAppearanceNameAqua') + + else: # Dark (Transparent only on win32) + appearance = NSAppearance.appearanceNamed_('NSAppearanceNameDarkAqua') + for window in NSApplication.sharedApplication().windows(): window.setStyleMask_(window.styleMask() & ~( NSMiniaturizableWindowMask | NSResizableWindowMask)) # disable zoom @@ -426,14 +435,30 @@ class _Theme(object): GetWindowLongW = ctypes.windll.user32.GetWindowLongW # noqa: N806 # ctypes SetWindowLongW = ctypes.windll.user32.SetWindowLongW # noqa: N806 # ctypes - root.overrideredirect(theme and True or False) - root.attributes("-transparentcolor", theme > 1 and 'grey4' or '') + # FIXME: Lose the "treat this like a boolean" bullshit + 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.update_idletasks() # Size and windows styles get recalculated here hwnd = ctypes.windll.user32.GetParent(root.winfo_id()) 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.wait_visibility() # need main window to be displayed before returning @@ -446,11 +471,25 @@ class _Theme(object): children = Window() nchildren = c_uint() 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, - PropModeReplace, theme and motif_wm_hints_dark or motif_wm_hints_normal, 5) + if theme == self.THEME_DEFAULT: + 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) + 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.wait_visibility() # need main window to be displayed before returning