From ebc34d858c4943ffc8ec6c131ebc974ca52363fb Mon Sep 17 00:00:00 2001 From: A_D Date: Fri, 11 Sep 2020 22:46:03 +0200 Subject: [PATCH 01/17] autoformatted and sorted imports --- prefs.py | 284 +++++++++++++++++++++++++++++-------------------------- 1 file changed, 149 insertions(+), 135 deletions(-) diff --git a/prefs.py b/prefs.py index cdc0ab3c..ab364ba2 100644 --- a/prefs.py +++ b/prefs.py @@ -1,24 +1,23 @@ # -*- coding: utf-8 -*- -from os.path import dirname, expanduser, expandvars, exists, isdir, join, normpath -from sys import platform -import webbrowser - +import logging import tkinter as tk -from tkinter import ttk +import webbrowser +from os.path import exists, expanduser, expandvars, join, normpath +from sys import platform from tkinter import colorchooser as tkColorChooser -from ttkHyperlinkLabel import HyperlinkLabel -import myNotebook as nb +from tkinter import ttk -from config import appname, applongname, config, appversion +import myNotebook as nb +import plug +from config import applongname, appname, appversion, config +from EDMCLogging import edmclogger from hotkey import hotkeymgr from l10n import Translations from monitor import monitor from theme import theme +from ttkHyperlinkLabel import HyperlinkLabel -import plug -import logging logger = logging.getLogger(appname) -from EDMCLogging import edmclogger ########################################################################### # Versioned preferences, so we know whether to set an 'on' default on @@ -26,6 +25,8 @@ from EDMCLogging import edmclogger ########################################################################### # May be imported by plugins + + class PrefsVersion(object): versions = { '0.0.0.0': 1, @@ -33,8 +34,9 @@ class PrefsVersion(object): '3.4.6.0': 3, '3.5.1.0': 4, # Only add new versions that add new Preferences - 'current': 4, # Should always match the last specific version, but only increment after you've added the new version. Guess at it if anticipating a new version. - } + # Should always match the last specific version, but only increment after you've added the new version. Guess at it if anticipating a new version. + 'current': 4, + } def __init__(self): return @@ -58,7 +60,7 @@ class PrefsVersion(object): # # config.get('PrefsVersion') is the version preferences we last saved for ########################################################################### - def shouldSetDefaults(self, addedAfter: str, oldTest : bool=True) -> bool: + def shouldSetDefaults(self, addedAfter: str, oldTest: bool = True) -> bool: pv = config.getint('PrefsVersion') # If no PrefsVersion yet exists then return oldTest if not pv: @@ -81,6 +83,7 @@ class PrefsVersion(object): return False ########################################################################### + prefsVersion = PrefsVersion() ########################################################################### @@ -96,7 +99,7 @@ if platform == 'darwin': objc.loadBundleVariables(HIServices, globals(), [('kAXTrustedCheckOptionPrompt', '@^{__CFString=}')]) was_accessible_at_launch = AXIsProcessTrusted() -elif platform=='win32': +elif platform == 'win32': # sigh tkFileDialog.askdirectory doesn't support unicode on Windows import ctypes from ctypes.wintypes import * @@ -108,10 +111,10 @@ elif platform=='win32': LoadString.argtypes = [HINSTANCE, UINT, LPWSTR, ctypes.c_int] # https://msdn.microsoft.com/en-us/library/windows/desktop/bb762115 - BIF_RETURNONLYFSDIRS = 0x00000001 - BIF_USENEWUI = 0x00000050 - BFFM_INITIALIZED = 1 - BFFM_SETSELECTION = 0x00000467 + BIF_RETURNONLYFSDIRS = 0x00000001 + BIF_USENEWUI = 0x00000050 + BFFM_INITIALIZED = 1 + BFFM_SETSELECTION = 0x00000467 BrowseCallbackProc = ctypes.WINFUNCTYPE(ctypes.c_int, HWND, ctypes.c_uint, LPARAM, LPARAM) class BROWSEINFO(ctypes.Structure): @@ -124,9 +127,10 @@ elif platform=='win32': GetParent.argtypes = [HWND] GetWindowRect = ctypes.windll.user32.GetWindowRect GetWindowRect.argtypes = [HWND, ctypes.POINTER(RECT)] - except: # Not supported under Wine 4.0 + except: # Not supported under Wine 4.0 CalculatePopupWindowPosition = None + class PreferencesDialog(tk.Toplevel): def __init__(self, parent, callback): @@ -134,47 +138,46 @@ class PreferencesDialog(tk.Toplevel): self.parent = parent self.callback = callback - self.title(platform=='darwin' and _('Preferences') or - _('Settings')) + self.title(platform == 'darwin' and _('Preferences') or _('Settings')) if parent.winfo_viewable(): self.transient(parent) # position over parent - if platform!='darwin' or parent.winfo_rooty()>0: # http://core.tcl.tk/tk/tktview/c84f660833546b1b84e7 + if platform != 'darwin' or parent.winfo_rooty() > 0: # http://core.tcl.tk/tk/tktview/c84f660833546b1b84e7 self.geometry("+%d+%d" % (parent.winfo_rootx(), parent.winfo_rooty())) # remove decoration - if platform=='win32': + if platform == 'win32': self.attributes('-toolwindow', tk.TRUE) - elif platform=='darwin': + elif platform == 'darwin': # http://wiki.tcl.tk/13428 parent.call('tk::unsupported::MacWindowStyle', 'style', self, 'utility') self.resizable(tk.FALSE, tk.FALSE) - self.cmdr = False # Note if Cmdr changes in the Journal - self.is_beta = False # Note if Beta status changes in the Journal + self.cmdr = False # Note if Cmdr changes in the Journal + self.is_beta = False # Note if Beta status changes in the Journal self.cmdrchanged_alarm = None frame = ttk.Frame(self) frame.grid(sticky=tk.NSEW) notebook = nb.Notebook(frame) - notebook.bind('<>', self.tabchanged) # Recompute on tab change + notebook.bind('<>', self.tabchanged) # Recompute on tab change PADX = 10 - BUTTONX = 12 # indent Checkbuttons and Radiobuttons - PADY = 2 # close spacing + BUTTONX = 12 # indent Checkbuttons and Radiobuttons + PADY = 2 # close spacing outframe = nb.Frame(notebook) outframe.columnconfigure(0, weight=1) if prefsVersion.shouldSetDefaults('0.0.0.0', not bool(config.getint('output'))): - output = config.OUT_SHIP # default settings + output = config.OUT_SHIP # default settings else: output = config.getint('output') - #TODO: *All* of this needs to use a 'row' variable, incremented after + # TODO: *All* of this needs to use a 'row' variable, incremented after # adding one to keep track, so it's easier to insert new rows in # the middle without worrying about updating `row=X` elements. self.out_label = nb.Label(outframe, text=_('Please choose what data to save')) @@ -182,27 +185,27 @@ class PreferencesDialog(tk.Toplevel): self.out_csv = tk.IntVar(value = (output & config.OUT_MKT_CSV ) and 1) self.out_csv_button = nb.Checkbutton(outframe, text=_('Market data in CSV format file'), variable=self.out_csv, command=self.outvarchanged) self.out_csv_button.grid(columnspan=2, padx=BUTTONX, sticky=tk.W) - self.out_td = tk.IntVar(value = (output & config.OUT_MKT_TD ) and 1) + self.out_td = tk.IntVar(value=(output & config.OUT_MKT_TD) and 1) self.out_td_button = nb.Checkbutton(outframe, text=_('Market data in Trade Dangerous format file'), variable=self.out_td, command=self.outvarchanged) self.out_td_button.grid(columnspan=2, padx=BUTTONX, sticky=tk.W) - self.out_ship= tk.IntVar(value = (output & config.OUT_SHIP and 1)) - self.out_ship_button = nb.Checkbutton(outframe, text=_('Ship loadout'), variable=self.out_ship, command=self.outvarchanged) # Output setting - self.out_ship_button.grid(columnspan=2, padx=BUTTONX, pady=(5,0), sticky=tk.W) - self.out_auto = tk.IntVar(value = 0 if output & config.OUT_MKT_MANUAL else 1) # inverted - self.out_auto_button = nb.Checkbutton(outframe, text=_('Automatically update on docking'), variable=self.out_auto, command=self.outvarchanged) # Output setting - self.out_auto_button.grid(columnspan=2, padx=BUTTONX, pady=(5,0), sticky=tk.W) + self.out_ship = tk.IntVar(value=(output & config.OUT_SHIP and 1)) + self.out_ship_button = nb.Checkbutton(outframe, text=_('Ship loadout'), variable=self.out_ship, command=self.outvarchanged) # Output setting + self.out_ship_button.grid(columnspan=2, padx=BUTTONX, pady=(5, 0), sticky=tk.W) + self.out_auto = tk.IntVar(value=0 if output & config.OUT_MKT_MANUAL else 1) # inverted + self.out_auto_button = nb.Checkbutton(outframe, text=_('Automatically update on docking'), variable=self.out_auto, command=self.outvarchanged) # Output setting + self.out_auto_button.grid(columnspan=2, padx=BUTTONX, pady=(5, 0), sticky=tk.W) self.outdir = tk.StringVar() self.outdir.set(config.get('outdir')) - self.outdir_label = nb.Label(outframe, text=_('File location')+':') # Section heading in settings - self.outdir_label.grid(padx=PADX, pady=(5,0), sticky=tk.W) + self.outdir_label = nb.Label(outframe, text=_('File location')+':') # Section heading in settings + self.outdir_label.grid(padx=PADX, pady=(5, 0), sticky=tk.W) self.outdir_entry = nb.Entry(outframe, takefocus=False) - self.outdir_entry.grid(columnspan=2, padx=PADX, pady=(0,PADY), sticky=tk.EW) - self.outbutton = nb.Button(outframe, text=(platform=='darwin' and _('Change...') or # Folder selection button on OSX - _('Browse...')), # Folder selection button on Windows - command = lambda:self.filebrowse(_('File location'), self.outdir)) + self.outdir_entry.grid(columnspan=2, padx=PADX, pady=(0, PADY), sticky=tk.EW) + self.outbutton = nb.Button(outframe, text=(platform == 'darwin' and _('Change...') or # Folder selection button on OSX + _('Browse...')), # Folder selection button on Windows + command=lambda: self.filebrowse(_('File location'), self.outdir)) self.outbutton.grid(column=1, padx=PADX, pady=PADY, sticky=tk.NSEW) - nb.Frame(outframe).grid(pady=5) # bottom spacer + nb.Frame(outframe).grid(pady=5) # bottom spacer notebook.add(outframe, text=_('Output')) # Tab heading in settings @@ -219,76 +222,84 @@ class PreferencesDialog(tk.Toplevel): self.logdir.set(config.get('journaldir') or config.default_journal_dir or '') self.logdir_entry = nb.Entry(configframe, takefocus=False) - nb.Label(configframe, text = _('E:D journal file location')+':').grid(columnspan=4, padx=PADX, sticky=tk.W) # Location of the new Journal file in E:D 2.2 - self.logdir_entry.grid(columnspan=4, padx=PADX, pady=(0,PADY), sticky=tk.EW) - self.logbutton = nb.Button(configframe, text=(platform=='darwin' and _('Change...') or # Folder selection button on OSX - _('Browse...')), # Folder selection button on Windows - command = lambda:self.filebrowse(_('E:D journal file location'), self.logdir)) + nb.Label(configframe, text=_('E:D journal file location')+':').grid(columnspan=4, padx=PADX, sticky=tk.W) # Location of the new Journal file in E:D 2.2 + self.logdir_entry.grid(columnspan=4, padx=PADX, pady=(0, PADY), sticky=tk.EW) + self.logbutton = nb.Button(configframe, text=(platform == 'darwin' and _('Change...') or # Folder selection button on OSX + _('Browse...')), # Folder selection button on Windows + command=lambda: self.filebrowse(_('E:D journal file location'), self.logdir)) self.logbutton.grid(row=10, column=3, padx=PADX, pady=PADY, sticky=tk.EW) if config.default_journal_dir: - nb.Button(configframe, text=_('Default'), command=self.logdir_reset, state = config.get('journaldir') and tk.NORMAL or tk.DISABLED).grid(row=10, column=2, pady=PADY, sticky=tk.EW) # Appearance theme and language setting + nb.Button(configframe, text=_('Default'), command=self.logdir_reset, state=config.get('journaldir') and tk.NORMAL or tk.DISABLED).grid(row=10, column=2, pady=PADY, sticky=tk.EW) # Appearance theme and language setting - if platform in ['darwin','win32']: + if platform in ['darwin', 'win32']: ttk.Separator(configframe, orient=tk.HORIZONTAL).grid(columnspan=4, padx=PADX, pady=PADY*4, sticky=tk.EW) self.hotkey_code = config.getint('hotkey_code') self.hotkey_mods = config.getint('hotkey_mods') - self.hotkey_only = tk.IntVar(value = not config.getint('hotkey_always')) - self.hotkey_play = tk.IntVar(value = not config.getint('hotkey_mute')) - nb.Label(configframe, text = platform=='darwin' and - _('Keyboard shortcut') or # Hotkey/Shortcut settings prompt on OSX + self.hotkey_only = tk.IntVar(value=not config.getint('hotkey_always')) + self.hotkey_play = tk.IntVar(value=not config.getint('hotkey_mute')) + nb.Label(configframe, text=platform == 'darwin' and + _('Keyboard shortcut') or # Hotkey/Shortcut settings prompt on OSX _('Hotkey') # Hotkey/Shortcut settings prompt on Windows - ).grid(row=20, padx=PADX, sticky=tk.W) + ).grid(row=20, padx=PADX, sticky=tk.W) if platform == 'darwin' and not was_accessible_at_launch: if AXIsProcessTrusted(): - nb.Label(configframe, text = _('Re-start {APP} to use shortcuts').format(APP=applongname), foreground='firebrick').grid(padx=PADX, sticky=tk.W) # Shortcut settings prompt on OSX + nb.Label(configframe, text=_('Re-start {APP} to use shortcuts').format(APP=applongname), + foreground='firebrick').grid(padx=PADX, sticky=tk.W) # Shortcut settings prompt on OSX else: - nb.Label(configframe, text = _('{APP} needs permission to use shortcuts').format(APP=applongname), foreground='firebrick').grid(columnspan=4, padx=PADX, sticky=tk.W) # Shortcut settings prompt on OSX - nb.Button(configframe, text = _('Open System Preferences'), command = self.enableshortcuts).grid(padx=PADX, sticky=tk.E) # Shortcut settings button on OSX + nb.Label(configframe, text=_('{APP} needs permission to use shortcuts').format( + APP=applongname), foreground='firebrick').grid(columnspan=4, padx=PADX, sticky=tk.W) # Shortcut settings prompt on OSX + nb.Button(configframe, text=_('Open System Preferences'), command=self.enableshortcuts).grid( + padx=PADX, sticky=tk.E) # Shortcut settings button on OSX else: - self.hotkey_text = nb.Entry(configframe, width = (platform == 'darwin' and 20 or 30), justify=tk.CENTER) - self.hotkey_text.insert(0, self.hotkey_code and hotkeymgr.display(self.hotkey_code, self.hotkey_mods) or _('None')) # No hotkey/shortcut currently defined + self.hotkey_text = nb.Entry(configframe, width=(platform == 'darwin' and 20 or 30), justify=tk.CENTER) + self.hotkey_text.insert(0, self.hotkey_code and hotkeymgr.display( + self.hotkey_code, self.hotkey_mods) or _('None')) # No hotkey/shortcut currently defined self.hotkey_text.bind('', self.hotkeystart) self.hotkey_text.bind('', self.hotkeyend) - self.hotkey_text.grid(row=20, column=1, columnspan=2, pady=(5,0), sticky=tk.W) - self.hotkey_only_btn = nb.Checkbutton(configframe, text=_('Only when Elite: Dangerous is the active app'), variable=self.hotkey_only, state = self.hotkey_code and tk.NORMAL or tk.DISABLED) # Hotkey/Shortcut setting - self.hotkey_only_btn.grid(columnspan=4, padx=PADX, pady=(5,0), sticky=tk.W) - self.hotkey_play_btn = nb.Checkbutton(configframe, text=_('Play sound'), variable=self.hotkey_play, state = self.hotkey_code and tk.NORMAL or tk.DISABLED) # Hotkey/Shortcut setting + self.hotkey_text.grid(row=20, column=1, columnspan=2, pady=(5, 0), sticky=tk.W) + self.hotkey_only_btn = nb.Checkbutton(configframe, text=_('Only when Elite: Dangerous is the active app'), variable=self.hotkey_only, state=self.hotkey_code and tk.NORMAL or tk.DISABLED) # Hotkey/Shortcut setting + self.hotkey_only_btn.grid(columnspan=4, padx=PADX, pady=(5, 0), sticky=tk.W) + self.hotkey_play_btn = nb.Checkbutton(configframe, text=_('Play sound'), variable=self.hotkey_play, state=self.hotkey_code and tk.NORMAL or tk.DISABLED) # Hotkey/Shortcut setting self.hotkey_play_btn.grid(columnspan=4, padx=PADX, sticky=tk.W) # Option to disabled Automatic Check For Updates whilst in-game ttk.Separator(configframe, orient=tk.HORIZONTAL).grid(columnspan=4, padx=PADX, pady=PADY*4, sticky=tk.EW) - self.disable_autoappupdatecheckingame = tk.IntVar(value = config.getint('disable_autoappupdatecheckingame')) - self.disable_autoappupdatecheckingame_btn = nb.Checkbutton(configframe, text=_('Disable Automatic Application Updates Check when in-game'), variable=self.disable_autoappupdatecheckingame, command=self.disable_autoappupdatecheckingame_changed) + self.disable_autoappupdatecheckingame = tk.IntVar(value=config.getint('disable_autoappupdatecheckingame')) + self.disable_autoappupdatecheckingame_btn = nb.Checkbutton(configframe, text=_( + 'Disable Automatic Application Updates Check when in-game'), variable=self.disable_autoappupdatecheckingame, command=self.disable_autoappupdatecheckingame_changed) self.disable_autoappupdatecheckingame_btn.grid(columnspan=4, padx=PADX, sticky=tk.W) - ttk.Separator(configframe, orient=tk.HORIZONTAL).grid(columnspan=4, padx=PADX, pady=PADY*4, sticky=tk.EW) - nb.Label(configframe, text=_('Preferred websites')).grid(row=30, columnspan=4, padx=PADX, sticky=tk.W) # Settings prompt for preferred ship loadout, system and station info websites + # Settings prompt for preferred ship loadout, system and station info websites + nb.Label(configframe, text=_('Preferred websites')).grid(row=30, columnspan=4, padx=PADX, sticky=tk.W) - self.shipyard_provider = tk.StringVar(value = config.get('shipyard_provider') in plug.provides('shipyard_url') and config.get('shipyard_provider') or 'EDSY') - nb.Label(configframe, text=_('Shipyard')).grid(row=31, padx=PADX, pady=2*PADY, sticky=tk.W) # Setting to decide which ship outfitting website to link to - either E:D Shipyard or Coriolis - self.shipyard_button = nb.OptionMenu(configframe, self.shipyard_provider, self.shipyard_provider.get(), *plug.provides('shipyard_url')) - self.shipyard_button.configure(width = 15) + self.shipyard_provider = tk.StringVar(value=config.get('shipyard_provider') in plug.provides('shipyard_url') and config.get('shipyard_provider') or 'EDSY') + # Setting to decide which ship outfitting website to link to - either E:D Shipyard or Coriolis + nb.Label(configframe, text=_('Shipyard')).grid(row=31, padx=PADX, pady=2*PADY, sticky=tk.W) + self.shipyard_button = nb.OptionMenu(configframe, self.shipyard_provider, + self.shipyard_provider.get(), *plug.provides('shipyard_url')) + self.shipyard_button.configure(width=15) self.shipyard_button.grid(row=31, column=1, sticky=tk.W) # Option for alternate URL opening - self.alt_shipyard_open = tk.IntVar(value = config.getint('use_alt_shipyard_open')) + self.alt_shipyard_open = tk.IntVar(value=config.getint('use_alt_shipyard_open')) self.alt_shipyard_open_btn = nb.Checkbutton(configframe, - text=_('Use alternate URL method'), - variable=self.alt_shipyard_open, - command=self.alt_shipyard_open_changed, - ) + text=_('Use alternate URL method'), + variable=self.alt_shipyard_open, + command=self.alt_shipyard_open_changed, + ) self.alt_shipyard_open_btn.grid(row=31, column=2, sticky=tk.W) - self.system_provider = tk.StringVar(value = config.get('system_provider') in plug.provides('system_url') and config.get('system_provider') or 'EDSM') + self.system_provider = tk.StringVar(value=config.get('system_provider') in plug.provides( + 'system_url') and config.get('system_provider') or 'EDSM') nb.Label(configframe, text=_('System')).grid(row=32, padx=PADX, pady=2*PADY, sticky=tk.W) - self.system_button = nb.OptionMenu(configframe, self.system_provider, self.system_provider.get(), *plug.provides('system_url')) - self.system_button.configure(width = 15) + self.system_button = nb.OptionMenu(configframe, self.system_provider,self.system_provider.get(), *plug.provides('system_url')) + self.system_button.configure(width=15) self.system_button.grid(row=32, column=1, sticky=tk.W) - self.station_provider = tk.StringVar(value = config.get('station_provider') in plug.provides('station_url') and config.get('station_provider') or 'eddb') + self.station_provider = tk.StringVar(value=config.get('station_provider') in plug.provides('station_url') and config.get('station_provider') or 'eddb') nb.Label(configframe, text=_('Station')).grid(row=33, padx=PADX, pady=2*PADY, sticky=tk.W) self.station_button = nb.OptionMenu(configframe, self.station_provider, self.station_provider.get(), *plug.provides('station_url')) - self.station_button.configure(width = 15) + self.station_button.configure(width=15) self.station_button.grid(row=33, column=1, sticky=tk.W) # Set loglevel @@ -306,36 +317,38 @@ class PreferencesDialog(tk.Toplevel): # Big spacer nb.Label(configframe).grid(sticky=tk.W) - notebook.add(configframe, text=_('Configuration')) # Tab heading in settings - + notebook.add(configframe, text=_('Configuration')) # Tab heading in settings self.languages = Translations.available_names() - self.lang = tk.StringVar(value = self.languages.get(config.get('language'), _('Default'))) # Appearance theme and language setting - self.always_ontop = tk.BooleanVar(value = config.getint('always_ontop')) - self.theme = tk.IntVar(value = config.getint('theme')) + self.lang = tk.StringVar(value=self.languages.get(config.get('language'), _('Default'))) # Appearance theme and language setting + self.always_ontop = tk.BooleanVar(value=config.getint('always_ontop')) + self.theme = tk.IntVar(value=config.getint('theme')) self.theme_colors = [config.get('dark_text'), config.get('dark_highlight')] self.theme_prompts = [ _('Normal text'), # Dark theme color setting - _('Highlighted text'), # Dark theme color setting + _('Highlighted text'), # Dark theme color setting ] themeframe = nb.Frame(notebook) themeframe.columnconfigure(2, weight=1) - nb.Label(themeframe, text=_('Language')).grid(row=10, padx=PADX, sticky=tk.W) # Appearance setting prompt + nb.Label(themeframe, text=_('Language')).grid(row=10, padx=PADX, sticky=tk.W) # Appearance setting prompt self.lang_button = nb.OptionMenu(themeframe, self.lang, self.lang.get(), *self.languages.values()) self.lang_button.grid(row=10, column=1, columnspan=2, padx=PADX, sticky=tk.W) ttk.Separator(themeframe, orient=tk.HORIZONTAL).grid(columnspan=3, padx=PADX, pady=PADY*4, sticky=tk.EW) - nb.Label(themeframe, text=_('Theme')).grid(columnspan=3, padx=PADX, sticky=tk.W) # Appearance setting - nb.Radiobutton(themeframe, text=_('Default'), variable=self.theme, value=0, command=self.themevarchanged).grid(columnspan=3, padx=BUTTONX, sticky=tk.W) # Appearance theme and language setting - nb.Radiobutton(themeframe, text=_('Dark'), variable=self.theme, value=1, command=self.themevarchanged).grid(columnspan=3, padx=BUTTONX, sticky=tk.W) # Appearance theme setting + nb.Label(themeframe, text=_('Theme')).grid(columnspan=3, padx=PADX, sticky=tk.W) # Appearance setting + nb.Radiobutton(themeframe, text=_('Default'), variable=self.theme, value=0, command=self.themevarchanged).grid( + columnspan=3, padx=BUTTONX, sticky=tk.W) # Appearance theme and language setting + nb.Radiobutton(themeframe, text=_('Dark'), variable=self.theme, value=1, command=self.themevarchanged).grid( + columnspan=3, padx=BUTTONX, sticky=tk.W) # Appearance theme setting if platform == 'win32': - nb.Radiobutton(themeframe, text=_('Transparent'), variable=self.theme, value=2, command=self.themevarchanged).grid(columnspan=3, padx=BUTTONX, sticky=tk.W) # Appearance theme setting + nb.Radiobutton(themeframe, text=_('Transparent'), variable=self.theme, value=2, command=self.themevarchanged).grid( + columnspan=3, padx=BUTTONX, sticky=tk.W) # Appearance theme setting self.theme_label_0 = nb.Label(themeframe, text=self.theme_prompts[0]) self.theme_label_0.grid(row=20, padx=PADX, sticky=tk.W) - self.theme_button_0 = nb.ColoredButton(themeframe, text=_('Station'), background='grey4', command=lambda:self.themecolorbrowse(0)) # Main window + self.theme_button_0 = nb.ColoredButton(themeframe, text=_('Station'), background='grey4', command=lambda: self.themecolorbrowse(0)) # Main window self.theme_button_0.grid(row=20, column=1, padx=PADX, pady=PADY, sticky=tk.NSEW) self.theme_label_1 = nb.Label(themeframe, text=self.theme_prompts[1]) self.theme_label_1.grid(row=21, padx=PADX, sticky=tk.W) - self.theme_button_1 = nb.ColoredButton(themeframe, text=' Hutton Orbital ', background='grey4', command=lambda:self.themecolorbrowse(1)) # Do not translate + self.theme_button_1 = nb.ColoredButton(themeframe, text=' Hutton Orbital ', background='grey4', command=lambda: self.themecolorbrowse(1)) # Do not translate self.theme_button_1.grid(row=21, column=1, padx=PADX, pady=PADY, sticky=tk.NSEW) # UI Scaling @@ -369,10 +382,10 @@ class PreferencesDialog(tk.Toplevel): # Always on top ttk.Separator(themeframe, orient=tk.HORIZONTAL).grid(columnspan=3, padx=PADX, pady=PADY*4, sticky=tk.EW) self.ontop_button = nb.Checkbutton(themeframe, text=_('Always on top'), variable=self.always_ontop, command=self.themevarchanged) - self.ontop_button.grid(columnspan=3, padx=BUTTONX, sticky=tk.W) # Appearance setting - nb.Label(themeframe).grid(sticky=tk.W) # big spacer + self.ontop_button.grid(columnspan=3, padx=BUTTONX, sticky=tk.W) # Appearance setting + nb.Label(themeframe).grid(sticky=tk.W) # big spacer - notebook.add(themeframe, text=_('Appearance')) # Tab heading in settings + notebook.add(themeframe, text=_('Appearance')) # Tab heading in settings # Plugin settings and info plugsframe = nb.Frame(notebook) @@ -380,21 +393,21 @@ class PreferencesDialog(tk.Toplevel): plugdir = tk.StringVar() plugdir.set(config.plugin_dir) - nb.Label(plugsframe, text=_('Plugins folder')+':').grid(padx=PADX, sticky=tk.W) # Section heading in settings + nb.Label(plugsframe, text=_('Plugins folder')+':').grid(padx=PADX, sticky=tk.W) # Section heading in settings plugdirentry = nb.Entry(plugsframe, justify=tk.LEFT) self.displaypath(plugdir, plugdirentry) plugdirentry.grid(row=10, padx=PADX, sticky=tk.EW) - nb.Button(plugsframe, text=_('Open'), # Button that opens a folder in Explorer/Finder - command=lambda: webbrowser.open('file:///%s' % plugdir.get())).grid(row=10, column=1, padx=(0,PADX), sticky=tk.NSEW) + nb.Button(plugsframe, text=_('Open'), # Button that opens a folder in Explorer/Finder + command=lambda: webbrowser.open('file:///%s' % plugdir.get())).grid(row=10, column=1, padx=(0, PADX), sticky=tk.NSEW) - nb.Label(plugsframe, text=_("Tip: You can disable a plugin by{CR}adding '{EXT}' to its folder name").format(EXT='.disabled')).grid( # Help text in settings + nb.Label(plugsframe, text=_("Tip: You can disable a plugin by{CR}adding '{EXT}' to its folder name").format(EXT='.disabled')).grid( # Help text in settings columnspan=2, padx=PADX, pady=10, sticky=tk.NSEW) enabled_plugins = [x for x in plug.PLUGINS if x.folder and x.module] if len(enabled_plugins): ttk.Separator(plugsframe, orient=tk.HORIZONTAL).grid(columnspan=3, padx=PADX, pady=PADY * 8, sticky=tk.EW) - nb.Label(plugsframe, text=_('Enabled Plugins')+':').grid(padx=PADX, sticky=tk.W) # List of plugins in settings + nb.Label(plugsframe, text=_('Enabled Plugins')+':').grid(padx=PADX, sticky=tk.W) # List of plugins in settings for plugin in enabled_plugins: if plugin.name == plugin.folder: label = nb.Label(plugsframe, text=plugin.name) @@ -409,34 +422,34 @@ class PreferencesDialog(tk.Toplevel): ttk.Separator(plugsframe, orient=tk.HORIZONTAL).grid(columnspan=3, padx=PADX, pady=PADY * 8, sticky=tk.EW) nb.Label(plugsframe, text=_('Plugins Without Python 3.x Support:')+':').grid(padx=PADX, sticky=tk.W) for plugin in plug.PLUGINS_not_py3: - if plugin.folder: # 'system' ones have this set to None to suppress listing in Plugins prefs tab + if plugin.folder: # 'system' ones have this set to None to suppress listing in Plugins prefs tab nb.Label(plugsframe, text=plugin.name).grid(columnspan=2, padx=PADX*2, sticky=tk.W) HyperlinkLabel(plugsframe, text=_('Information on migrating plugins'), background=nb.Label().cget('background'), url='https://github.com/EDCD/EDMarketConnector/blob/main/PLUGINS.md#migration-to-python-37', underline=True - ).grid(columnspan=2, padx=PADX, sticky=tk.W) + ).grid(columnspan=2, padx=PADX, sticky=tk.W) ############################################################ disabled_plugins = [x for x in plug.PLUGINS if x.folder and not x.module] if len(disabled_plugins): ttk.Separator(plugsframe, orient=tk.HORIZONTAL).grid(columnspan=3, padx=PADX, pady=PADY * 8, sticky=tk.EW) - nb.Label(plugsframe, text=_('Disabled Plugins')+':').grid(padx=PADX, sticky=tk.W) # List of plugins in settings + nb.Label(plugsframe, text=_('Disabled Plugins')+':').grid(padx=PADX, sticky=tk.W) # List of plugins in settings for plugin in disabled_plugins: nb.Label(plugsframe, text=plugin.name).grid(columnspan=2, padx=PADX*2, sticky=tk.W) notebook.add(plugsframe, text=_('Plugins')) # Tab heading in settings - if platform=='darwin': - self.protocol("WM_DELETE_WINDOW", self.apply) # close button applies changes + if platform == 'darwin': + self.protocol("WM_DELETE_WINDOW", self.apply) # close button applies changes else: buttonframe = ttk.Frame(frame) buttonframe.grid(padx=PADX, pady=PADX, sticky=tk.NSEW) buttonframe.columnconfigure(0, weight=1) - ttk.Label(buttonframe).grid(row=0, column=0) # spacer + ttk.Label(buttonframe).grid(row=0, column=0) # spacer button = ttk.Button(buttonframe, text=_('OK'), command=self.apply) button.grid(row=0, column=1, sticky=tk.E) - button.bind("", lambda event:self.apply()) + button.bind("", lambda event: self.apply()) self.protocol("WM_DELETE_WINDOW", self._destroy) # Selectively disable buttons depending on output settings @@ -448,7 +461,7 @@ class PreferencesDialog(tk.Toplevel): # wait for window to appear on screen before calling grab_set self.parent.update_idletasks() - self.parent.wm_attributes('-topmost', 0) # needed for dialog to appear ontop of parent on OSX & Linux + self.parent.wm_attributes('-topmost', 0) # needed for dialog to appear ontop of parent on OSX & Linux self.wait_visibility() self.grab_set() @@ -492,10 +505,10 @@ class PreferencesDialog(tk.Toplevel): self.out_label['state'] = self.out_csv_button['state'] = self.out_td_button['state'] = self.out_ship_button['state'] = tk.NORMAL or tk.DISABLED local = self.out_td.get() or self.out_csv.get() or self.out_ship.get() - self.out_auto_button['state'] = local and logvalid and tk.NORMAL or tk.DISABLED - self.outdir_label['state'] = local and tk.NORMAL or tk.DISABLED - self.outbutton['state'] = local and tk.NORMAL or tk.DISABLED - self.outdir_entry['state'] = local and 'readonly' or tk.DISABLED + self.out_auto_button['state'] = local and logvalid and tk.NORMAL or tk.DISABLED + self.outdir_label['state'] = local and tk.NORMAL or tk.DISABLED + self.outbutton['state'] = local and tk.NORMAL or tk.DISABLED + self.outdir_entry['state'] = local and 'readonly' or tk.DISABLED def filebrowse(self, title, pathvar): import tkinter.filedialog @@ -511,9 +524,9 @@ class PreferencesDialog(tk.Toplevel): self.outvarchanged() def displaypath(self, pathvar, entryfield): - entryfield['state'] = tk.NORMAL # must be writable to update + entryfield['state'] = tk.NORMAL # must be writable to update entryfield.delete(0, tk.END) - if platform=='win32': + if platform == 'win32': start = pathvar.get().lower().startswith(config.home.lower()) and len(config.home.split('\\')) or 0 display = [] components = normpath(pathvar.get()).split('\\') @@ -522,14 +535,14 @@ class PreferencesDialog(tk.Toplevel): for i in range(start, len(components)): try: if (not SHGetLocalizedName('\\'.join(components[:i+1]), buf, MAX_PATH, ctypes.byref(pidsRes)) and - LoadString(ctypes.WinDLL(expandvars(buf.value))._handle, pidsRes.value, buf, MAX_PATH)): + LoadString(ctypes.WinDLL(expandvars(buf.value))._handle, pidsRes.value, buf, MAX_PATH)): display.append(buf.value) else: display.append(components[i]) except: display.append(components[i]) entryfield.insert(0, '\\'.join(display)) - elif platform=='darwin' and NSFileManager.defaultManager().componentsToDisplayForPath_(pathvar.get()): # None if path doesn't exist + elif platform == 'darwin' and NSFileManager.defaultManager().componentsToDisplayForPath_(pathvar.get()): # None if path doesn't exist if pathvar.get().startswith(config.home): display = ['~'] + NSFileManager.defaultManager().componentsToDisplayForPath_(pathvar.get())[len(NSFileManager.defaultManager().componentsToDisplayForPath_(config.home)):] else: @@ -555,7 +568,8 @@ class PreferencesDialog(tk.Toplevel): config.set('use_alt_shipyard_open', self.alt_shipyard_open.get()) def themecolorbrowse(self, index): - (rgb, color) = tkColorChooser.askcolor(self.theme_colors[index], title=self.theme_prompts[index], parent=self.parent) + (rgb, color) = tkColorChooser.askcolor( + self.theme_colors[index], title=self.theme_prompts[index], parent=self.parent) if color: self.theme_colors[index] = color self.themevarchanged() @@ -578,9 +592,10 @@ class PreferencesDialog(tk.Toplevel): def hotkeyend(self, event): event.widget.unbind('') event.widget.unbind('') - hotkeymgr.acquire_stop() # in case focus was lost while in the middle of acquiring + hotkeymgr.acquire_stop() # in case focus was lost while in the middle of acquiring event.widget.delete(0, tk.END) - self.hotkey_text.insert(0, self.hotkey_code and hotkeymgr.display(self.hotkey_code, self.hotkey_mods) or _('None')) # No hotkey/shortcut currently defined + self.hotkey_text.insert(0, self.hotkey_code and hotkeymgr.display( + self.hotkey_code, self.hotkey_mods) or _('None')) # No hotkey/shortcut currently defined def hotkeylisten(self, event): good = hotkeymgr.fromevent(event) @@ -593,7 +608,7 @@ class PreferencesDialog(tk.Toplevel): (self.hotkey_code, self.hotkey_mods) = (hotkey_code, hotkey_mods) self.hotkey_only_btn['state'] = tk.NORMAL self.hotkey_play_btn['state'] = tk.NORMAL - self.hotkey_only_btn.focus() # move to next widget - calls hotkeyend() implicitly + self.hotkey_only_btn.focus() # move to next widget - calls hotkeyend() implicitly else: if good is None: # clear (self.hotkey_code, self.hotkey_mods) = (0, 0) @@ -603,18 +618,17 @@ class PreferencesDialog(tk.Toplevel): self.hotkey_only_btn['state'] = tk.NORMAL self.hotkey_play_btn['state'] = tk.NORMAL else: - event.widget.insert(0, _('None')) # No hotkey/shortcut currently defined + event.widget.insert(0, _('None')) # No hotkey/shortcut currently defined self.hotkey_only_btn['state'] = tk.DISABLED self.hotkey_play_btn['state'] = tk.DISABLED - self.hotkey_only_btn.focus() # move to next widget - calls hotkeyend() implicitly - return('break') # stops further processing - insertion, Tab traversal etc - + self.hotkey_only_btn.focus() # move to next widget - calls hotkeyend() implicitly + return('break') # stops further processing - insertion, Tab traversal etc def apply(self): config.set('PrefsVersion', prefsVersion.stringToSerial(appversion)) config.set('output', - (self.out_td.get() and config.OUT_MKT_TD) + - (self.out_csv.get() and config.OUT_MKT_CSV) + + (self.out_td.get() and config.OUT_MKT_TD) + + (self.out_csv.get() and config.OUT_MKT_CSV) + (config.OUT_MKT_MANUAL if not self.out_auto.get() else 0) + (self.out_ship.get() and config.OUT_SHIP) + (config.getint('output') & (config.OUT_MKT_EDDN | config.OUT_SYS_EDDN | config.OUT_SYS_DELAY))) @@ -622,11 +636,11 @@ class PreferencesDialog(tk.Toplevel): logdir = self.logdir.get() if config.default_journal_dir and logdir.lower() == config.default_journal_dir.lower(): - config.set('journaldir', '') # default location + config.set('journaldir', '') # default location else: config.set('journaldir', logdir) - if platform in ['darwin','win32']: + if platform in ['darwin', 'win32']: config.set('hotkey_code', self.hotkey_code) config.set('hotkey_mods', self.hotkey_mods) config.set('hotkey_always', int(not self.hotkey_only.get())) @@ -637,7 +651,7 @@ class PreferencesDialog(tk.Toplevel): config.set('loglevel', self.select_loglevel.get()) edmclogger.get_streamhandler().setLevel(self.select_loglevel.get()) - lang_codes = { v: k for k, v in self.languages.items() } # Codes by name + lang_codes = {v: k for k, v in self.languages.items()} # Codes by name config.set('language', lang_codes.get(self.lang.get()) or '') Translations.install(config.get('language') or None) From 9f8d8a90523fde3d93f042af81723e848525af17 Mon Sep 17 00:00:00 2001 From: A_D Date: Fri, 11 Sep 2020 23:13:34 +0200 Subject: [PATCH 02/17] cleaned up overlong lines --- prefs.py | 290 +++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 238 insertions(+), 52 deletions(-) diff --git a/prefs.py b/prefs.py index ab364ba2..5c1906ac 100644 --- a/prefs.py +++ b/prefs.py @@ -34,9 +34,10 @@ class PrefsVersion(object): '3.4.6.0': 3, '3.5.1.0': 4, # Only add new versions that add new Preferences - # Should always match the last specific version, but only increment after you've added the new version. Guess at it if anticipating a new version. + # Should always match the last specific version, but only increment after you've added the new version. + # Guess at it if anticipating a new version. 'current': 4, - } + } def __init__(self): return @@ -74,7 +75,11 @@ class PrefsVersion(object): aa = self.versions[addedAfter] # Sanity check, if something was added after then current should be greater if aa >= self.versions['current']: - raise Exception('ERROR: Call to prefs.py:PrefsVersion.shouldSetDefaults() with "addedAfter" >= current latest in "versions" table. You probably need to increase "current" serial number.') + raise Exception( + 'ERROR: Call to prefs.py:PrefsVersion.shouldSetDefaults() with ' + '"addedAfter" >= current latest in "versions" table.' + ' You probably need to increase "current" serial number.' + ) # If this preference was added after the saved PrefsVersion we should set defaults if aa >= pv: @@ -93,9 +98,18 @@ if platform == 'darwin': try: from ApplicationServices import AXIsProcessTrusted, AXIsProcessTrustedWithOptions, kAXTrustedCheckOptionPrompt except: - HIServices = objc.loadBundle('HIServices', globals(), '/System/Library/Frameworks/ApplicationServices.framework/Frameworks/HIServices.framework') - objc.loadBundleFunctions(HIServices, globals(), [('AXIsProcessTrusted', 'B'), - ('AXIsProcessTrustedWithOptions', 'B@')]) + HIServices = objc.loadBundle( + 'HIServices', + globals(), + '/System/Library/Frameworks/ApplicationServices.framework/Frameworks/HIServices.framework' + ) + + objc.loadBundleFunctions( + HIServices, + globals(), + [('AXIsProcessTrusted', 'B'), ('AXIsProcessTrustedWithOptions', 'B@')] + ) + objc.loadBundleVariables(HIServices, globals(), [('kAXTrustedCheckOptionPrompt', '@^{__CFString=}')]) was_accessible_at_launch = AXIsProcessTrusted() @@ -118,11 +132,27 @@ elif platform == 'win32': BrowseCallbackProc = ctypes.WINFUNCTYPE(ctypes.c_int, HWND, ctypes.c_uint, LPARAM, LPARAM) class BROWSEINFO(ctypes.Structure): - _fields_ = [("hwndOwner", HWND), ("pidlRoot", LPVOID), ("pszDisplayName", LPWSTR), ("lpszTitle", LPCWSTR), ("ulFlags", UINT), ("lpfn", BrowseCallbackProc), ("lParam", LPCWSTR), ("iImage", ctypes.c_int)] + _fields_ = [ + ("hwndOwner", HWND), + ("pidlRoot", LPVOID), + ("pszDisplayName", LPWSTR), + ("lpszTitle", LPCWSTR), + ("ulFlags", UINT), + ("lpfn", BrowseCallbackProc), + ("lParam", LPCWSTR), + ("iImage", ctypes.c_int) + ] try: CalculatePopupWindowPosition = ctypes.windll.user32.CalculatePopupWindowPosition - CalculatePopupWindowPosition.argtypes = [ctypes.POINTER(POINT), ctypes.POINTER(SIZE), UINT, ctypes.POINTER(RECT), ctypes.POINTER(RECT)] + CalculatePopupWindowPosition.argtypes = [ + ctypes.POINTER(POINT), + ctypes.POINTER(SIZE), + UINT, + ctypes.POINTER(RECT), + ctypes.POINTER(RECT) + ] + GetParent = ctypes.windll.user32.GetParent GetParent.argtypes = [HWND] GetWindowRect = ctypes.windll.user32.GetWindowRect @@ -182,17 +212,44 @@ class PreferencesDialog(tk.Toplevel): # the middle without worrying about updating `row=X` elements. self.out_label = nb.Label(outframe, text=_('Please choose what data to save')) self.out_label.grid(columnspan=2, padx=PADX, sticky=tk.W) - self.out_csv = tk.IntVar(value = (output & config.OUT_MKT_CSV ) and 1) - self.out_csv_button = nb.Checkbutton(outframe, text=_('Market data in CSV format file'), variable=self.out_csv, command=self.outvarchanged) + self.out_csv = tk.IntVar(value=(output & config.OUT_MKT_CSV) and 1) + self.out_csv_button = nb.Checkbutton( + outframe, + text=_('Market data in CSV format file'), + variable=self.out_csv, + command=self.outvarchanged + ) + self.out_csv_button.grid(columnspan=2, padx=BUTTONX, sticky=tk.W) self.out_td = tk.IntVar(value=(output & config.OUT_MKT_TD) and 1) - self.out_td_button = nb.Checkbutton(outframe, text=_('Market data in Trade Dangerous format file'), variable=self.out_td, command=self.outvarchanged) + self.out_td_button = nb.Checkbutton( + outframe, + text=_('Market data in Trade Dangerous format file'), + variable=self.out_td, + command=self.outvarchanged + ) + self.out_td_button.grid(columnspan=2, padx=BUTTONX, sticky=tk.W) self.out_ship = tk.IntVar(value=(output & config.OUT_SHIP and 1)) - self.out_ship_button = nb.Checkbutton(outframe, text=_('Ship loadout'), variable=self.out_ship, command=self.outvarchanged) # Output setting + + # Output setting + self.out_ship_button = nb.Checkbutton( + outframe, + text=_('Ship loadout'), + variable=self.out_ship, + command=self.outvarchanged + ) self.out_ship_button.grid(columnspan=2, padx=BUTTONX, pady=(5, 0), sticky=tk.W) self.out_auto = tk.IntVar(value=0 if output & config.OUT_MKT_MANUAL else 1) # inverted - self.out_auto_button = nb.Checkbutton(outframe, text=_('Automatically update on docking'), variable=self.out_auto, command=self.outvarchanged) # Output setting + + # Output setting + self.out_auto_button = nb.Checkbutton( + outframe, + text=_('Automatically update on docking'), + variable=self.out_auto, + command=self.outvarchanged + ) + self.out_auto_button.grid(columnspan=2, padx=BUTTONX, pady=(5, 0), sticky=tk.W) self.outdir = tk.StringVar() @@ -201,9 +258,12 @@ class PreferencesDialog(tk.Toplevel): self.outdir_label.grid(padx=PADX, pady=(5, 0), sticky=tk.W) self.outdir_entry = nb.Entry(outframe, takefocus=False) self.outdir_entry.grid(columnspan=2, padx=PADX, pady=(0, PADY), sticky=tk.EW) - self.outbutton = nb.Button(outframe, text=(platform == 'darwin' and _('Change...') or # Folder selection button on OSX - _('Browse...')), # Folder selection button on Windows - command=lambda: self.filebrowse(_('File location'), self.outdir)) + self.outbutton = nb.Button( + outframe, + text=(platform == 'darwin' and _('Change...') or _('Browse...')), + command=lambda: self.filebrowse(_('File location'), self.outdir) + ) + self.outbutton.grid(column=1, padx=PADX, pady=PADY, sticky=tk.NSEW) nb.Frame(outframe).grid(pady=5) # bottom spacer @@ -222,14 +282,28 @@ class PreferencesDialog(tk.Toplevel): self.logdir.set(config.get('journaldir') or config.default_journal_dir or '') self.logdir_entry = nb.Entry(configframe, takefocus=False) - nb.Label(configframe, text=_('E:D journal file location')+':').grid(columnspan=4, padx=PADX, sticky=tk.W) # Location of the new Journal file in E:D 2.2 + # Location of the new Journal file in E:D 2.2 + nb.Label( + configframe, + text=_('E:D journal file location')+':' + ).grid(columnspan=4, padx=PADX, sticky=tk.W) + self.logdir_entry.grid(columnspan=4, padx=PADX, pady=(0, PADY), sticky=tk.EW) - self.logbutton = nb.Button(configframe, text=(platform == 'darwin' and _('Change...') or # Folder selection button on OSX - _('Browse...')), # Folder selection button on Windows - command=lambda: self.filebrowse(_('E:D journal file location'), self.logdir)) + self.logbutton = nb.Button( + configframe, + text=(platform == 'darwin' and _('Change...') or _('Browse...')), + command=lambda: self.filebrowse(_('E:D journal file location'), self.logdir) + ) + self.logbutton.grid(row=10, column=3, padx=PADX, pady=PADY, sticky=tk.EW) if config.default_journal_dir: - nb.Button(configframe, text=_('Default'), command=self.logdir_reset, state=config.get('journaldir') and tk.NORMAL or tk.DISABLED).grid(row=10, column=2, pady=PADY, sticky=tk.EW) # Appearance theme and language setting + # Appearance theme and language setting + nb.Button( + configframe, + text=_('Default'), + command=self.logdir_reset, + state=config.get('journaldir') and tk.NORMAL or tk.DISABLED + ).grid(row=10, column=2, pady=PADY, sticky=tk.EW) if platform in ['darwin', 'win32']: ttk.Separator(configframe, orient=tk.HORIZONTAL).grid(columnspan=4, padx=PADX, pady=PADY*4, sticky=tk.EW) @@ -246,8 +320,14 @@ class PreferencesDialog(tk.Toplevel): nb.Label(configframe, text=_('Re-start {APP} to use shortcuts').format(APP=applongname), foreground='firebrick').grid(padx=PADX, sticky=tk.W) # Shortcut settings prompt on OSX else: - nb.Label(configframe, text=_('{APP} needs permission to use shortcuts').format( - APP=applongname), foreground='firebrick').grid(columnspan=4, padx=PADX, sticky=tk.W) # Shortcut settings prompt on OSX + # Shortcut settings prompt on OSX + nb.Label( + configframe, + text=_('{APP} needs permission to use shortcuts').format( + APP=applongname + ), + foreground='firebrick' + ).grid(columnspan=4, padx=PADX, sticky=tk.W) nb.Button(configframe, text=_('Open System Preferences'), command=self.enableshortcuts).grid( padx=PADX, sticky=tk.E) # Shortcut settings button on OSX else: @@ -257,23 +337,47 @@ class PreferencesDialog(tk.Toplevel): self.hotkey_text.bind('', self.hotkeystart) self.hotkey_text.bind('', self.hotkeyend) self.hotkey_text.grid(row=20, column=1, columnspan=2, pady=(5, 0), sticky=tk.W) - self.hotkey_only_btn = nb.Checkbutton(configframe, text=_('Only when Elite: Dangerous is the active app'), variable=self.hotkey_only, state=self.hotkey_code and tk.NORMAL or tk.DISABLED) # Hotkey/Shortcut setting + + # Hotkey/Shortcut setting + self.hotkey_only_btn = nb.Checkbutton( + configframe, + text=_('Only when Elite: Dangerous is the active app'), + variable=self.hotkey_only, + state=self.hotkey_code and tk.NORMAL or tk.DISABLED + ) + self.hotkey_only_btn.grid(columnspan=4, padx=PADX, pady=(5, 0), sticky=tk.W) - self.hotkey_play_btn = nb.Checkbutton(configframe, text=_('Play sound'), variable=self.hotkey_play, state=self.hotkey_code and tk.NORMAL or tk.DISABLED) # Hotkey/Shortcut setting + + # Hotkey/Shortcut setting + self.hotkey_play_btn = nb.Checkbutton( + configframe, + text=_('Play sound'), + variable=self.hotkey_play, + state=self.hotkey_code and tk.NORMAL or tk.DISABLED + ) + self.hotkey_play_btn.grid(columnspan=4, padx=PADX, sticky=tk.W) # Option to disabled Automatic Check For Updates whilst in-game ttk.Separator(configframe, orient=tk.HORIZONTAL).grid(columnspan=4, padx=PADX, pady=PADY*4, sticky=tk.EW) self.disable_autoappupdatecheckingame = tk.IntVar(value=config.getint('disable_autoappupdatecheckingame')) - self.disable_autoappupdatecheckingame_btn = nb.Checkbutton(configframe, text=_( - 'Disable Automatic Application Updates Check when in-game'), variable=self.disable_autoappupdatecheckingame, command=self.disable_autoappupdatecheckingame_changed) + self.disable_autoappupdatecheckingame_btn = nb.Checkbutton( + configframe, + text=_('Disable Automatic Application Updates Check when in-game'), + variable=self.disable_autoappupdatecheckingame, + command=self.disable_autoappupdatecheckingame_changed + ) + self.disable_autoappupdatecheckingame_btn.grid(columnspan=4, padx=PADX, sticky=tk.W) ttk.Separator(configframe, orient=tk.HORIZONTAL).grid(columnspan=4, padx=PADX, pady=PADY*4, sticky=tk.EW) # Settings prompt for preferred ship loadout, system and station info websites nb.Label(configframe, text=_('Preferred websites')).grid(row=30, columnspan=4, padx=PADX, sticky=tk.W) - self.shipyard_provider = tk.StringVar(value=config.get('shipyard_provider') in plug.provides('shipyard_url') and config.get('shipyard_provider') or 'EDSY') + self.shipyard_provider = tk.StringVar( + value=(config.get('shipyard_provider') in plug.provides('shipyard_url') + and config.get('shipyard_provider') or 'EDSY') + ) # Setting to decide which ship outfitting website to link to - either E:D Shipyard or Coriolis nb.Label(configframe, text=_('Shipyard')).grid(row=31, padx=PADX, pady=2*PADY, sticky=tk.W) self.shipyard_button = nb.OptionMenu(configframe, self.shipyard_provider, @@ -289,28 +393,62 @@ class PreferencesDialog(tk.Toplevel): ) self.alt_shipyard_open_btn.grid(row=31, column=2, sticky=tk.W) - self.system_provider = tk.StringVar(value=config.get('system_provider') in plug.provides( - 'system_url') and config.get('system_provider') or 'EDSM') + self.system_provider = tk.StringVar( + value=config.get('system_provider') in plug.provides('system_url') + and config.get('system_provider') or 'EDSM' + ) + nb.Label(configframe, text=_('System')).grid(row=32, padx=PADX, pady=2*PADY, sticky=tk.W) - self.system_button = nb.OptionMenu(configframe, self.system_provider,self.system_provider.get(), *plug.provides('system_url')) + self.system_button = nb.OptionMenu( + configframe, + self.system_provider, + self.system_provider.get(), + *plug.provides('system_url') + ) self.system_button.configure(width=15) self.system_button.grid(row=32, column=1, sticky=tk.W) - self.station_provider = tk.StringVar(value=config.get('station_provider') in plug.provides('station_url') and config.get('station_provider') or 'eddb') + self.station_provider = tk.StringVar( + value=config.get('station_provider') in plug.provides('station_url') + and config.get('station_provider') or 'eddb' + ) + nb.Label(configframe, text=_('Station')).grid(row=33, padx=PADX, pady=2*PADY, sticky=tk.W) - self.station_button = nb.OptionMenu(configframe, self.station_provider, self.station_provider.get(), *plug.provides('station_url')) + self.station_button = nb.OptionMenu( + configframe, + self.station_provider, + self.station_provider.get(), + *plug.provides('station_url') + ) + self.station_button.configure(width=15) self.station_button.grid(row=33, column=1, sticky=tk.W) # Set loglevel ttk.Separator(configframe, orient=tk.HORIZONTAL).grid(columnspan=4, padx=PADX, pady=PADY*4, sticky=tk.EW) - nb.Label(configframe, text=_('Log Level')).grid(row=35, padx=PADX, pady=2*PADY, sticky=tk.W) # Set the current loglevel + + # Set the current loglevel + nb.Label( + configframe, + text=_('Log Level') + ).grid(row=35, padx=PADX, pady=2*PADY, sticky=tk.W) + current_loglevel = config.get('loglevel') if not current_loglevel: current_loglevel = logging.getLevelName(logging.INFO) self.select_loglevel = tk.StringVar(value=current_loglevel) - loglevels = [logging.getLevelName(l) for l in (logging.CRITICAL, logging.ERROR, logging.WARNING, logging.INFO, logging.DEBUG)] - self.loglevel_dropdown = nb.OptionMenu(configframe, self.select_loglevel, self.select_loglevel.get(), *loglevels) + loglevels = [ + logging.getLevelName(l) for l in ( + logging.CRITICAL, logging.ERROR, logging.WARNING, logging.INFO, logging.DEBUG + ) + ] + + self.loglevel_dropdown = nb.OptionMenu( + configframe, + self.select_loglevel, + self.select_loglevel.get(), + *loglevels + ) self.loglevel_dropdown.configure(width=15) self.loglevel_dropdown.grid(row=35, column=1, sticky=tk.W) @@ -320,7 +458,8 @@ class PreferencesDialog(tk.Toplevel): notebook.add(configframe, text=_('Configuration')) # Tab heading in settings self.languages = Translations.available_names() - self.lang = tk.StringVar(value=self.languages.get(config.get('language'), _('Default'))) # Appearance theme and language setting + # Appearance theme and language setting + self.lang = tk.StringVar(value=self.languages.get(config.get('language'), _('Default'))) self.always_ontop = tk.BooleanVar(value=config.getint('always_ontop')) self.theme = tk.IntVar(value=config.getint('theme')) self.theme_colors = [config.get('dark_text'), config.get('dark_highlight')] @@ -340,15 +479,32 @@ class PreferencesDialog(tk.Toplevel): nb.Radiobutton(themeframe, text=_('Dark'), variable=self.theme, value=1, command=self.themevarchanged).grid( columnspan=3, padx=BUTTONX, sticky=tk.W) # Appearance theme setting if platform == 'win32': - nb.Radiobutton(themeframe, text=_('Transparent'), variable=self.theme, value=2, command=self.themevarchanged).grid( - columnspan=3, padx=BUTTONX, sticky=tk.W) # Appearance theme setting + nb.Radiobutton( + themeframe, + text=_('Transparent'), # Appearance theme setting + variable=self.theme, + value=2, + command=self.themevarchanged + ).grid(columnspan=3, padx=BUTTONX, sticky=tk.W) self.theme_label_0 = nb.Label(themeframe, text=self.theme_prompts[0]) self.theme_label_0.grid(row=20, padx=PADX, sticky=tk.W) - self.theme_button_0 = nb.ColoredButton(themeframe, text=_('Station'), background='grey4', command=lambda: self.themecolorbrowse(0)) # Main window + + # Main window + self.theme_button_0 = nb.ColoredButton( + themeframe, + text=_('Station'), + background='grey4', + command=lambda: self.themecolorbrowse(0) + ) self.theme_button_0.grid(row=20, column=1, padx=PADX, pady=PADY, sticky=tk.NSEW) self.theme_label_1 = nb.Label(themeframe, text=self.theme_prompts[1]) self.theme_label_1.grid(row=21, padx=PADX, sticky=tk.W) - self.theme_button_1 = nb.ColoredButton(themeframe, text=' Hutton Orbital ', background='grey4', command=lambda: self.themecolorbrowse(1)) # Do not translate + self.theme_button_1 = nb.ColoredButton( + themeframe, + text=' Hutton Orbital ', # Do not translate + background='grey4', + command=lambda: self.themecolorbrowse(1) + ) self.theme_button_1.grid(row=21, column=1, padx=PADX, pady=PADY, sticky=tk.NSEW) # UI Scaling @@ -381,7 +537,13 @@ class PreferencesDialog(tk.Toplevel): # Always on top ttk.Separator(themeframe, orient=tk.HORIZONTAL).grid(columnspan=3, padx=PADX, pady=PADY*4, sticky=tk.EW) - self.ontop_button = nb.Checkbutton(themeframe, text=_('Always on top'), variable=self.always_ontop, command=self.themevarchanged) + self.ontop_button = nb.Checkbutton( + themeframe, + text=_('Always on top'), + variable=self.always_ontop, + command=self.themevarchanged + ) + self.ontop_button.grid(columnspan=3, padx=BUTTONX, sticky=tk.W) # Appearance setting nb.Label(themeframe).grid(sticky=tk.W) # big spacer @@ -398,16 +560,25 @@ class PreferencesDialog(tk.Toplevel): self.displaypath(plugdir, plugdirentry) plugdirentry.grid(row=10, padx=PADX, sticky=tk.EW) - nb.Button(plugsframe, text=_('Open'), # Button that opens a folder in Explorer/Finder - command=lambda: webbrowser.open('file:///%s' % plugdir.get())).grid(row=10, column=1, padx=(0, PADX), sticky=tk.NSEW) + nb.Button( + plugsframe, + text=_('Open'), # Button that opens a folder in Explorer/Finder + command=lambda: webbrowser.open('file:///%s' % plugdir.get()) + ).grid(row=10, column=1, padx=(0, PADX), sticky=tk.NSEW) - nb.Label(plugsframe, text=_("Tip: You can disable a plugin by{CR}adding '{EXT}' to its folder name").format(EXT='.disabled')).grid( # Help text in settings - columnspan=2, padx=PADX, pady=10, sticky=tk.NSEW) + nb.Label( + plugsframe, + # Help text in settings + text=_("Tip: You can disable a plugin by{CR}adding '{EXT}' to its folder name").format(EXT='.disabled') + ).grid(columnspan=2, padx=PADX, pady=10, sticky=tk.NSEW) enabled_plugins = [x for x in plug.PLUGINS if x.folder and x.module] if len(enabled_plugins): ttk.Separator(plugsframe, orient=tk.HORIZONTAL).grid(columnspan=3, padx=PADX, pady=PADY * 8, sticky=tk.EW) - nb.Label(plugsframe, text=_('Enabled Plugins')+':').grid(padx=PADX, sticky=tk.W) # List of plugins in settings + nb.Label( + plugsframe, + text=_('Enabled Plugins')+':' # List of plugins in settings + ).grid(padx=PADX, sticky=tk.W) for plugin in enabled_plugins: if plugin.name == plugin.folder: label = nb.Label(plugsframe, text=plugin.name) @@ -434,7 +605,11 @@ class PreferencesDialog(tk.Toplevel): disabled_plugins = [x for x in plug.PLUGINS if x.folder and not x.module] if len(disabled_plugins): ttk.Separator(plugsframe, orient=tk.HORIZONTAL).grid(columnspan=3, padx=PADX, pady=PADY * 8, sticky=tk.EW) - nb.Label(plugsframe, text=_('Disabled Plugins')+':').grid(padx=PADX, sticky=tk.W) # List of plugins in settings + nb.Label( + plugsframe, + text=_('Disabled Plugins')+':' # List of plugins in settings + ).grid(padx=PADX, sticky=tk.W) + for plugin in disabled_plugins: nb.Label(plugsframe, text=plugin.name).grid(columnspan=2, padx=PADX*2, sticky=tk.W) @@ -503,7 +678,11 @@ class PreferencesDialog(tk.Toplevel): logdir = self.logdir.get() logvalid = logdir and exists(logdir) - self.out_label['state'] = self.out_csv_button['state'] = self.out_td_button['state'] = self.out_ship_button['state'] = tk.NORMAL or tk.DISABLED + self.out_label['state'] = tk.NORMAL + self.out_csv_button['state'] = tk.NORMAL + self.out_td_button['state'] = tk.NORMAL + self.out_ship_button['state'] = tk.NORMAL + local = self.out_td.get() or self.out_csv.get() or self.out_ship.get() self.out_auto_button['state'] = local and logvalid and tk.NORMAL or tk.DISABLED self.outdir_label['state'] = local and tk.NORMAL or tk.DISABLED @@ -542,9 +721,13 @@ class PreferencesDialog(tk.Toplevel): except: display.append(components[i]) entryfield.insert(0, '\\'.join(display)) - elif platform == 'darwin' and NSFileManager.defaultManager().componentsToDisplayForPath_(pathvar.get()): # None if path doesn't exist + + # None if path doesn't exist + elif platform == 'darwin' and NSFileManager.defaultManager().componentsToDisplayForPath_(pathvar.get()): if pathvar.get().startswith(config.home): - display = ['~'] + NSFileManager.defaultManager().componentsToDisplayForPath_(pathvar.get())[len(NSFileManager.defaultManager().componentsToDisplayForPath_(config.home)):] + display = ['~'] + NSFileManager.defaultManager().componentsToDisplayForPath_(pathvar.get())[ + len(NSFileManager.defaultManager().componentsToDisplayForPath_(config.home)): + ] else: display = NSFileManager.defaultManager().componentsToDisplayForPath_(pathvar.get()) entryfield.insert(0, '/'.join(display)) @@ -632,7 +815,10 @@ class PreferencesDialog(tk.Toplevel): (config.OUT_MKT_MANUAL if not self.out_auto.get() else 0) + (self.out_ship.get() and config.OUT_SHIP) + (config.getint('output') & (config.OUT_MKT_EDDN | config.OUT_SYS_EDDN | config.OUT_SYS_DELAY))) - config.set('outdir', self.outdir.get().startswith('~') and join(config.home, self.outdir.get()[2:]) or self.outdir.get()) + config.set( + 'outdir', + self.outdir.get().startswith('~') and join(config.home, self.outdir.get()[2:]) or self.outdir.get() + ) logdir = self.logdir.get() if config.default_journal_dir and logdir.lower() == config.default_journal_dir.lower(): From d77cfd0e7a4c3cfc557658ee32c82b6e497652c0 Mon Sep 17 00:00:00 2001 From: A_D Date: Fri, 11 Sep 2020 23:23:37 +0200 Subject: [PATCH 03/17] removed bare excepts --- prefs.py | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/prefs.py b/prefs.py index 5c1906ac..2a0e3d68 100644 --- a/prefs.py +++ b/prefs.py @@ -6,6 +6,7 @@ from os.path import exists, expanduser, expandvars, join, normpath from sys import platform from tkinter import colorchooser as tkColorChooser from tkinter import ttk +from typing import Callable, TYPE_CHECKING import myNotebook as nb import plug @@ -19,6 +20,10 @@ from ttkHyperlinkLabel import HyperlinkLabel logger = logging.getLogger(appname) +if TYPE_CHECKING: + def _(x: str) -> str: + return x + ########################################################################### # Versioned preferences, so we know whether to set an 'on' default on # 'new' preferences, or not. @@ -97,7 +102,7 @@ if platform == 'darwin': from Foundation import NSFileManager try: from ApplicationServices import AXIsProcessTrusted, AXIsProcessTrustedWithOptions, kAXTrustedCheckOptionPrompt - except: + except ImportError: HIServices = objc.loadBundle( 'HIServices', globals(), @@ -111,12 +116,13 @@ if platform == 'darwin': ) objc.loadBundleVariables(HIServices, globals(), [('kAXTrustedCheckOptionPrompt', '@^{__CFString=}')]) + was_accessible_at_launch = AXIsProcessTrusted() elif platform == 'win32': # sigh tkFileDialog.askdirectory doesn't support unicode on Windows import ctypes - from ctypes.wintypes import * + from ctypes.wintypes import HINSTANCE, HWND, LPARAM, LPCWSTR, LPVOID, LPWSTR, MAX_PATH, POINT, RECT, SIZE, UINT SHGetLocalizedName = ctypes.windll.shell32.SHGetLocalizedName SHGetLocalizedName.argtypes = [LPCWSTR, LPWSTR, UINT, ctypes.POINTER(ctypes.c_int)] @@ -157,7 +163,7 @@ elif platform == 'win32': GetParent.argtypes = [HWND] GetWindowRect = ctypes.windll.user32.GetWindowRect GetWindowRect.argtypes = [HWND, ctypes.POINTER(RECT)] - except: # Not supported under Wine 4.0 + except Exception: # Not supported under Wine 4.0 CalculatePopupWindowPosition = None @@ -718,7 +724,7 @@ class PreferencesDialog(tk.Toplevel): display.append(buf.value) else: display.append(components[i]) - except: + except Exception: display.append(components[i]) entryfield.insert(0, '\\'.join(display)) @@ -876,6 +882,6 @@ class PreferencesDialog(tk.Toplevel): anchor = [x for x in pane.anchors() if x.name() == 'Privacy_Accessibility'][0] anchor.reveal() prefs.activate() - except: + except Exception: AXIsProcessTrustedWithOptions({kAXTrustedCheckOptionPrompt: True}) self.parent.event_generate('<>', when="tail") From 742709c431e62fc54848b09df13b7aa89b1d36b1 Mon Sep 17 00:00:00 2001 From: A_D Date: Sat, 12 Sep 2020 01:39:10 +0200 Subject: [PATCH 04/17] Replaced modulo-formatting with fstrings --- prefs.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/prefs.py b/prefs.py index 2a0e3d68..8ee1e245 100644 --- a/prefs.py +++ b/prefs.py @@ -181,7 +181,7 @@ class PreferencesDialog(tk.Toplevel): # position over parent if platform != 'darwin' or parent.winfo_rooty() > 0: # http://core.tcl.tk/tk/tktview/c84f660833546b1b84e7 - self.geometry("+%d+%d" % (parent.winfo_rootx(), parent.winfo_rooty())) + self.geometry(f'+{parent.winfo_rootx()}+{parent.winfo_rooty()}') # remove decoration if platform == 'win32': @@ -569,7 +569,7 @@ class PreferencesDialog(tk.Toplevel): nb.Button( plugsframe, text=_('Open'), # Button that opens a folder in Explorer/Finder - command=lambda: webbrowser.open('file:///%s' % plugdir.get()) + command=lambda: webbrowser.open(f'file:///{plugdir.get()}') ).grid(row=10, column=1, padx=(0, PADX), sticky=tk.NSEW) nb.Label( @@ -589,7 +589,7 @@ class PreferencesDialog(tk.Toplevel): if plugin.name == plugin.folder: label = nb.Label(plugsframe, text=plugin.name) else: - label = nb.Label(plugsframe, text='%s (%s)' % (plugin.folder, plugin.name)) + label = nb.Label(plugsframe, text=f'{plugin.folder} ({plugin.name})') label.grid(columnspan=2, padx=PADX*2, sticky=tk.W) ############################################################ @@ -653,7 +653,7 @@ class PreferencesDialog(tk.Toplevel): if CalculatePopupWindowPosition(POINT(parent.winfo_rootx(), parent.winfo_rooty()), SIZE(position.right - position.left, position.bottom - position.top), 0x10000, None, position): - self.geometry("+%d+%d" % (position.left, position.top)) + self.geometry("+{position.left}+{position.top}") def cmdrchanged(self, event=None): if self.cmdr != monitor.cmdr or self.is_beta != monitor.is_beta: From 3010f2196581807eb37631aa5efcd1a9aadfe28b Mon Sep 17 00:00:00 2001 From: A_D Date: Sat, 12 Sep 2020 01:40:20 +0200 Subject: [PATCH 05/17] Added some type comments to appease pylance --- prefs.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/prefs.py b/prefs.py index 8ee1e245..598f352b 100644 --- a/prefs.py +++ b/prefs.py @@ -4,9 +4,9 @@ import tkinter as tk import webbrowser from os.path import exists, expanduser, expandvars, join, normpath from sys import platform -from tkinter import colorchooser as tkColorChooser +from tkinter import colorchooser as tkColorChooser # type: ignore from tkinter import ttk -from typing import Callable, TYPE_CHECKING +from typing import TYPE_CHECKING import myNotebook as nb import plug @@ -98,10 +98,12 @@ prefsVersion = PrefsVersion() ########################################################################### if platform == 'darwin': - import objc - from Foundation import NSFileManager + import objc # type: ignore + from Foundation import NSFileManager # type: ignore try: - from ApplicationServices import AXIsProcessTrusted, AXIsProcessTrustedWithOptions, kAXTrustedCheckOptionPrompt + from ApplicationServices import ( # type: ignore + AXIsProcessTrusted, AXIsProcessTrustedWithOptions, kAXTrustedCheckOptionPrompt + ) except ImportError: HIServices = objc.loadBundle( 'HIServices', @@ -117,11 +119,12 @@ if platform == 'darwin': objc.loadBundleVariables(HIServices, globals(), [('kAXTrustedCheckOptionPrompt', '@^{__CFString=}')]) - was_accessible_at_launch = AXIsProcessTrusted() + was_accessible_at_launch = AXIsProcessTrusted() # type: ignore elif platform == 'win32': # sigh tkFileDialog.askdirectory doesn't support unicode on Windows import ctypes + import ctypes.windll # type: ignore # I promise pylance, its there. from ctypes.wintypes import HINSTANCE, HWND, LPARAM, LPCWSTR, LPVOID, LPWSTR, MAX_PATH, POINT, RECT, SIZE, UINT SHGetLocalizedName = ctypes.windll.shell32.SHGetLocalizedName From b85b0622f575828b70edecbae153a5f9aa6f046a Mon Sep 17 00:00:00 2001 From: A_D Date: Sat, 12 Sep 2020 01:53:20 +0200 Subject: [PATCH 06/17] Fixed some type issues --- prefs.py | 38 ++++++++++++++++++++++---------------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/prefs.py b/prefs.py index 598f352b..a27eb0d2 100644 --- a/prefs.py +++ b/prefs.py @@ -262,9 +262,9 @@ class PreferencesDialog(tk.Toplevel): self.out_auto_button.grid(columnspan=2, padx=BUTTONX, pady=(5, 0), sticky=tk.W) self.outdir = tk.StringVar() - self.outdir.set(config.get('outdir')) + self.outdir.set(str(config.get('outdir'))) self.outdir_label = nb.Label(outframe, text=_('File location')+':') # Section heading in settings - self.outdir_label.grid(padx=PADX, pady=(5, 0), sticky=tk.W) + self.outdir_label.grid(padx=PADX, pady=(5, 0), sticky=tk.W) # type: ignore # 2 tuple does each side self.outdir_entry = nb.Entry(outframe, takefocus=False) self.outdir_entry.grid(columnspan=2, padx=PADX, pady=(0, PADY), sticky=tk.EW) self.outbutton = nb.Button( @@ -288,7 +288,7 @@ class PreferencesDialog(tk.Toplevel): configframe.columnconfigure(1, weight=1) self.logdir = tk.StringVar() - self.logdir.set(config.get('journaldir') or config.default_journal_dir or '') + self.logdir.set(str(config.get('journaldir') or config.default_journal_dir or '')) self.logdir_entry = nb.Entry(configframe, takefocus=False) # Location of the new Journal file in E:D 2.2 @@ -341,8 +341,13 @@ class PreferencesDialog(tk.Toplevel): padx=PADX, sticky=tk.E) # Shortcut settings button on OSX else: self.hotkey_text = nb.Entry(configframe, width=(platform == 'darwin' and 20 or 30), justify=tk.CENTER) - self.hotkey_text.insert(0, self.hotkey_code and hotkeymgr.display( - self.hotkey_code, self.hotkey_mods) or _('None')) # No hotkey/shortcut currently defined + self.hotkey_text.insert( + 0, + # No hotkey/shortcut currently defined + self.hotkey_code and hotkeymgr.display( # type: ignore # Only shows up on darwin or windows + self.hotkey_code, self.hotkey_mods + ) or _('None') + ) self.hotkey_text.bind('', self.hotkeystart) self.hotkey_text.bind('', self.hotkeyend) self.hotkey_text.grid(row=20, column=1, columnspan=2, pady=(5, 0), sticky=tk.W) @@ -384,8 +389,9 @@ class PreferencesDialog(tk.Toplevel): nb.Label(configframe, text=_('Preferred websites')).grid(row=30, columnspan=4, padx=PADX, sticky=tk.W) self.shipyard_provider = tk.StringVar( - value=(config.get('shipyard_provider') in plug.provides('shipyard_url') - and config.get('shipyard_provider') or 'EDSY') + value=str( + config.get('shipyard_provider') in plug.provides('shipyard_url') + and config.get('shipyard_provider') or 'EDSY') ) # Setting to decide which ship outfitting website to link to - either E:D Shipyard or Coriolis nb.Label(configframe, text=_('Shipyard')).grid(row=31, padx=PADX, pady=2*PADY, sticky=tk.W) @@ -403,8 +409,8 @@ class PreferencesDialog(tk.Toplevel): self.alt_shipyard_open_btn.grid(row=31, column=2, sticky=tk.W) self.system_provider = tk.StringVar( - value=config.get('system_provider') in plug.provides('system_url') - and config.get('system_provider') or 'EDSM' + value=str(config.get('system_provider') in plug.provides('system_url') + and config.get('system_provider') or 'EDSM') ) nb.Label(configframe, text=_('System')).grid(row=32, padx=PADX, pady=2*PADY, sticky=tk.W) @@ -418,8 +424,8 @@ class PreferencesDialog(tk.Toplevel): self.system_button.grid(row=32, column=1, sticky=tk.W) self.station_provider = tk.StringVar( - value=config.get('station_provider') in plug.provides('station_url') - and config.get('station_provider') or 'eddb' + value=str(config.get('station_provider') in plug.provides('station_url') + and config.get('station_provider') or 'eddb') ) nb.Label(configframe, text=_('Station')).grid(row=33, padx=PADX, pady=2*PADY, sticky=tk.W) @@ -445,7 +451,7 @@ class PreferencesDialog(tk.Toplevel): current_loglevel = config.get('loglevel') if not current_loglevel: current_loglevel = logging.getLevelName(logging.INFO) - self.select_loglevel = tk.StringVar(value=current_loglevel) + self.select_loglevel = tk.StringVar(value=str(current_loglevel)) loglevels = [ logging.getLevelName(l) for l in ( logging.CRITICAL, logging.ERROR, logging.WARNING, logging.INFO, logging.DEBUG @@ -469,7 +475,7 @@ class PreferencesDialog(tk.Toplevel): self.languages = Translations.available_names() # Appearance theme and language setting self.lang = tk.StringVar(value=self.languages.get(config.get('language'), _('Default'))) - self.always_ontop = tk.BooleanVar(value=config.getint('always_ontop')) + self.always_ontop = tk.BooleanVar(value=bool(config.getint('always_ontop'))) self.theme = tk.IntVar(value=config.getint('theme')) self.theme_colors = [config.get('dark_text'), config.get('dark_highlight')] self.theme_prompts = [ @@ -530,7 +536,7 @@ class PreferencesDialog(tk.Toplevel): self.ui_scale.set(config.getint('ui_scale')) self.uiscale_bar = tk.Scale( themeframe, - variable=self.ui_scale, + variable=self.ui_scale, # TODO: intvar, but annotated as DoubleVar orient=tk.HORIZONTAL, length=300 * (float(theme.startup_ui_scale) / 100.0 * theme.default_ui_scale), from_=0, @@ -848,7 +854,7 @@ class PreferencesDialog(tk.Toplevel): lang_codes = {v: k for k, v in self.languages.items()} # Codes by name config.set('language', lang_codes.get(self.lang.get()) or '') - Translations.install(config.get('language') or None) + Translations.install(config.get('language') or None) # type: ignore # This sets self in weird ways. config.set('ui_scale', self.ui_scale.get()) config.set('always_ontop', self.always_ontop.get()) @@ -877,7 +883,7 @@ class PreferencesDialog(tk.Toplevel): # popup System Preferences dialog try: # http://stackoverflow.com/questions/6652598/cocoa-button-opens-a-system-preference-page/6658201 - from ScriptingBridge import SBApplication + from ScriptingBridge import SBApplication # type: ignore sysprefs = 'com.apple.systempreferences' prefs = SBApplication.applicationWithBundleIdentifier_(sysprefs) pane = [x for x in prefs.panes() if x.id() == 'com.apple.preference.security'][0] From ef359395ecb213778348bd8098a45e8d8cc11357 Mon Sep 17 00:00:00 2001 From: A_D Date: Sat, 12 Sep 2020 01:53:49 +0200 Subject: [PATCH 07/17] Removed object subclass --- prefs.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/prefs.py b/prefs.py index a27eb0d2..b51b80c3 100644 --- a/prefs.py +++ b/prefs.py @@ -32,7 +32,7 @@ if TYPE_CHECKING: # May be imported by plugins -class PrefsVersion(object): +class PrefsVersion: versions = { '0.0.0.0': 1, '1.0.0.0': 2, From 2459de4893632332ae025c9b00efbd0d74b809dc Mon Sep 17 00:00:00 2001 From: A_D Date: Sat, 12 Sep 2020 02:01:21 +0200 Subject: [PATCH 08/17] Added spacing around scope changes --- prefs.py | 102 +++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 77 insertions(+), 25 deletions(-) diff --git a/prefs.py b/prefs.py index b51b80c3..f9b641a3 100644 --- a/prefs.py +++ b/prefs.py @@ -76,6 +76,7 @@ class PrefsVersion: if addedAfter not in self.versions: # Assume it was added at the start aa = 1 + else: aa = self.versions[addedAfter] # Sanity check, if something was added after then current should be greater @@ -104,6 +105,7 @@ if platform == 'darwin': from ApplicationServices import ( # type: ignore AXIsProcessTrusted, AXIsProcessTrustedWithOptions, kAXTrustedCheckOptionPrompt ) + except ImportError: HIServices = objc.loadBundle( 'HIServices', @@ -166,12 +168,12 @@ elif platform == 'win32': GetParent.argtypes = [HWND] GetWindowRect = ctypes.windll.user32.GetWindowRect GetWindowRect.argtypes = [HWND, ctypes.POINTER(RECT)] + except Exception: # Not supported under Wine 4.0 CalculatePopupWindowPosition = None class PreferencesDialog(tk.Toplevel): - def __init__(self, parent, callback): tk.Toplevel.__init__(self, parent) @@ -189,9 +191,11 @@ class PreferencesDialog(tk.Toplevel): # remove decoration if platform == 'win32': self.attributes('-toolwindow', tk.TRUE) + elif platform == 'darwin': # http://wiki.tcl.tk/13428 parent.call('tk::unsupported::MacWindowStyle', 'style', self, 'utility') + self.resizable(tk.FALSE, tk.FALSE) self.cmdr = False # Note if Cmdr changes in the Journal @@ -213,6 +217,7 @@ class PreferencesDialog(tk.Toplevel): if prefsVersion.shouldSetDefaults('0.0.0.0', not bool(config.getint('output'))): output = config.OUT_SHIP # default settings + else: output = config.getint('output') @@ -328,6 +333,7 @@ class PreferencesDialog(tk.Toplevel): if AXIsProcessTrusted(): nb.Label(configframe, text=_('Re-start {APP} to use shortcuts').format(APP=applongname), foreground='firebrick').grid(padx=PADX, sticky=tk.W) # Shortcut settings prompt on OSX + else: # Shortcut settings prompt on OSX nb.Label( @@ -339,6 +345,7 @@ class PreferencesDialog(tk.Toplevel): ).grid(columnspan=4, padx=PADX, sticky=tk.W) nb.Button(configframe, text=_('Open System Preferences'), command=self.enableshortcuts).grid( padx=PADX, sticky=tk.E) # Shortcut settings button on OSX + else: self.hotkey_text = nb.Entry(configframe, width=(platform == 'darwin' and 20 or 30), justify=tk.CENTER) self.hotkey_text.insert( @@ -348,6 +355,7 @@ class PreferencesDialog(tk.Toplevel): self.hotkey_code, self.hotkey_mods ) or _('None') ) + self.hotkey_text.bind('', self.hotkeystart) self.hotkey_text.bind('', self.hotkeyend) self.hotkey_text.grid(row=20, column=1, columnspan=2, pady=(5, 0), sticky=tk.W) @@ -395,17 +403,21 @@ class PreferencesDialog(tk.Toplevel): ) # Setting to decide which ship outfitting website to link to - either E:D Shipyard or Coriolis nb.Label(configframe, text=_('Shipyard')).grid(row=31, padx=PADX, pady=2*PADY, sticky=tk.W) - self.shipyard_button = nb.OptionMenu(configframe, self.shipyard_provider, - self.shipyard_provider.get(), *plug.provides('shipyard_url')) + self.shipyard_button = nb.OptionMenu( + configframe, self.shipyard_provider, self.shipyard_provider.get(), *plug.provides('shipyard_url') + ) + self.shipyard_button.configure(width=15) self.shipyard_button.grid(row=31, column=1, sticky=tk.W) # Option for alternate URL opening self.alt_shipyard_open = tk.IntVar(value=config.getint('use_alt_shipyard_open')) - self.alt_shipyard_open_btn = nb.Checkbutton(configframe, - text=_('Use alternate URL method'), - variable=self.alt_shipyard_open, - command=self.alt_shipyard_open_changed, - ) + self.alt_shipyard_open_btn = nb.Checkbutton( + configframe, + text=_('Use alternate URL method'), + variable=self.alt_shipyard_open, + command=self.alt_shipyard_open_changed, + ) + self.alt_shipyard_open_btn.grid(row=31, column=2, sticky=tk.W) self.system_provider = tk.StringVar( @@ -420,6 +432,7 @@ class PreferencesDialog(tk.Toplevel): self.system_provider.get(), *plug.provides('system_url') ) + self.system_button.configure(width=15) self.system_button.grid(row=32, column=1, sticky=tk.W) @@ -464,6 +477,7 @@ class PreferencesDialog(tk.Toplevel): self.select_loglevel.get(), *loglevels ) + self.loglevel_dropdown.configure(width=15) self.loglevel_dropdown.grid(row=35, column=1, sticky=tk.W) @@ -493,6 +507,7 @@ class PreferencesDialog(tk.Toplevel): columnspan=3, padx=BUTTONX, sticky=tk.W) # Appearance theme and language setting nb.Radiobutton(themeframe, text=_('Dark'), variable=self.theme, value=1, command=self.themevarchanged).grid( columnspan=3, padx=BUTTONX, sticky=tk.W) # Appearance theme setting + if platform == 'win32': nb.Radiobutton( themeframe, @@ -501,6 +516,7 @@ class PreferencesDialog(tk.Toplevel): value=2, command=self.themevarchanged ).grid(columnspan=3, padx=BUTTONX, sticky=tk.W) + self.theme_label_0 = nb.Label(themeframe, text=self.theme_prompts[0]) self.theme_label_0.grid(row=20, padx=PADX, sticky=tk.W) @@ -511,6 +527,7 @@ class PreferencesDialog(tk.Toplevel): background='grey4', command=lambda: self.themecolorbrowse(0) ) + self.theme_button_0.grid(row=20, column=1, padx=PADX, pady=PADY, sticky=tk.NSEW) self.theme_label_1 = nb.Label(themeframe, text=self.theme_prompts[1]) self.theme_label_1.grid(row=21, padx=PADX, sticky=tk.W) @@ -520,6 +537,7 @@ class PreferencesDialog(tk.Toplevel): background='grey4', command=lambda: self.themecolorbrowse(1) ) + self.theme_button_1.grid(row=21, column=1, padx=PADX, pady=PADY, sticky=tk.NSEW) # UI Scaling @@ -544,6 +562,7 @@ class PreferencesDialog(tk.Toplevel): tickinterval=50, resolution=10, ) + self.uiscale_bar.grid(row=23, column=1, sticky=tk.W) self.ui_scaling_defaultis = nb.Label( themeframe, @@ -594,9 +613,11 @@ class PreferencesDialog(tk.Toplevel): plugsframe, text=_('Enabled Plugins')+':' # List of plugins in settings ).grid(padx=PADX, sticky=tk.W) + for plugin in enabled_plugins: if plugin.name == plugin.folder: label = nb.Label(plugsframe, text=plugin.name) + else: label = nb.Label(plugsframe, text=f'{plugin.folder} ({plugin.name})') label.grid(columnspan=2, padx=PADX*2, sticky=tk.W) @@ -607,14 +628,17 @@ class PreferencesDialog(tk.Toplevel): if len(plug.PLUGINS_not_py3): ttk.Separator(plugsframe, orient=tk.HORIZONTAL).grid(columnspan=3, padx=PADX, pady=PADY * 8, sticky=tk.EW) nb.Label(plugsframe, text=_('Plugins Without Python 3.x Support:')+':').grid(padx=PADX, sticky=tk.W) + for plugin in plug.PLUGINS_not_py3: if plugin.folder: # 'system' ones have this set to None to suppress listing in Plugins prefs tab nb.Label(plugsframe, text=plugin.name).grid(columnspan=2, padx=PADX*2, sticky=tk.W) - HyperlinkLabel(plugsframe, text=_('Information on migrating plugins'), - background=nb.Label().cget('background'), - url='https://github.com/EDCD/EDMarketConnector/blob/main/PLUGINS.md#migration-to-python-37', - underline=True - ).grid(columnspan=2, padx=PADX, sticky=tk.W) + + HyperlinkLabel( + plugsframe, text=_('Information on migrating plugins'), + background=nb.Label().cget('background'), + url='https://github.com/EDCD/EDMarketConnector/blob/main/PLUGINS.md#migration-to-python-37', + underline=True + ).grid(columnspan=2, padx=PADX, sticky=tk.W) ############################################################ disabled_plugins = [x for x in plug.PLUGINS if x.folder and not x.module] @@ -632,6 +656,7 @@ class PreferencesDialog(tk.Toplevel): if platform == 'darwin': self.protocol("WM_DELETE_WINDOW", self.apply) # close button applies changes + else: buttonframe = ttk.Frame(frame) buttonframe.grid(padx=PADX, pady=PADX, sticky=tk.NSEW) @@ -659,9 +684,11 @@ class PreferencesDialog(tk.Toplevel): if platform == 'win32' and CalculatePopupWindowPosition: position = RECT() GetWindowRect(GetParent(self.winfo_id()), position) - if CalculatePopupWindowPosition(POINT(parent.winfo_rootx(), parent.winfo_rooty()), - SIZE(position.right - position.left, position.bottom - position.top), - 0x10000, None, position): + if CalculatePopupWindowPosition( + POINT(parent.winfo_rootx(), parent.winfo_rooty()), + SIZE(position.right - position.left, position.bottom - position.top), + 0x10000, None, position + ): self.geometry("+{position.left}+{position.top}") def cmdrchanged(self, event=None): @@ -669,6 +696,7 @@ class PreferencesDialog(tk.Toplevel): # Cmdr has changed - update settings if self.cmdr is not False: # Don't notify on first run plug.notify_prefs_cmdr_changed(monitor.cmdr, monitor.is_beta) + self.cmdr = monitor.cmdr self.is_beta = monitor.is_beta @@ -726,16 +754,19 @@ class PreferencesDialog(tk.Toplevel): components = normpath(pathvar.get()).split('\\') buf = ctypes.create_unicode_buffer(MAX_PATH) pidsRes = ctypes.c_int() - for i in range(start, len(components)): + for i in range(start, len(components)): # TODO: enumerate try: if (not SHGetLocalizedName('\\'.join(components[:i+1]), buf, MAX_PATH, ctypes.byref(pidsRes)) and LoadString(ctypes.WinDLL(expandvars(buf.value))._handle, pidsRes.value, buf, MAX_PATH)): display.append(buf.value) + else: display.append(components[i]) + except Exception: display.append(components[i]) - entryfield.insert(0, '\\'.join(display)) + + entryfield.insert(0, '\\'.join(display)) # TODO raw string # None if path doesn't exist elif platform == 'darwin' and NSFileManager.defaultManager().componentsToDisplayForPath_(pathvar.get()): @@ -743,19 +774,24 @@ class PreferencesDialog(tk.Toplevel): display = ['~'] + NSFileManager.defaultManager().componentsToDisplayForPath_(pathvar.get())[ len(NSFileManager.defaultManager().componentsToDisplayForPath_(config.home)): ] + else: display = NSFileManager.defaultManager().componentsToDisplayForPath_(pathvar.get()) + entryfield.insert(0, '/'.join(display)) else: if pathvar.get().startswith(config.home): entryfield.insert(0, '~' + pathvar.get()[len(config.home):]) + else: entryfield.insert(0, pathvar.get()) + entryfield['state'] = 'readonly' def logdir_reset(self): if config.default_journal_dir: self.logdir.set(config.default_journal_dir) + self.outvarchanged() def disable_autoappupdatecheckingame_changed(self): @@ -767,7 +803,9 @@ class PreferencesDialog(tk.Toplevel): def themecolorbrowse(self, index): (rgb, color) = tkColorChooser.askcolor( - self.theme_colors[index], title=self.theme_prompts[index], parent=self.parent) + self.theme_colors[index], title=self.theme_prompts[index], parent=self.parent + ) + if color: self.theme_colors[index] = color self.themevarchanged() @@ -807,29 +845,37 @@ class PreferencesDialog(tk.Toplevel): self.hotkey_only_btn['state'] = tk.NORMAL self.hotkey_play_btn['state'] = tk.NORMAL self.hotkey_only_btn.focus() # move to next widget - calls hotkeyend() implicitly + else: if good is None: # clear (self.hotkey_code, self.hotkey_mods) = (0, 0) event.widget.delete(0, tk.END) + if self.hotkey_code: event.widget.insert(0, hotkeymgr.display(self.hotkey_code, self.hotkey_mods)) self.hotkey_only_btn['state'] = tk.NORMAL self.hotkey_play_btn['state'] = tk.NORMAL + else: event.widget.insert(0, _('None')) # No hotkey/shortcut currently defined self.hotkey_only_btn['state'] = tk.DISABLED self.hotkey_play_btn['state'] = tk.DISABLED + self.hotkey_only_btn.focus() # move to next widget - calls hotkeyend() implicitly + return('break') # stops further processing - insertion, Tab traversal etc def apply(self): config.set('PrefsVersion', prefsVersion.stringToSerial(appversion)) - config.set('output', - (self.out_td.get() and config.OUT_MKT_TD) + - (self.out_csv.get() and config.OUT_MKT_CSV) + - (config.OUT_MKT_MANUAL if not self.out_auto.get() else 0) + - (self.out_ship.get() and config.OUT_SHIP) + - (config.getint('output') & (config.OUT_MKT_EDDN | config.OUT_SYS_EDDN | config.OUT_SYS_DELAY))) + config.set( + 'output', + (self.out_td.get() and config.OUT_MKT_TD) + + (self.out_csv.get() and config.OUT_MKT_CSV) + + (config.OUT_MKT_MANUAL if not self.out_auto.get() else 0) + + (self.out_ship.get() and config.OUT_SHIP) + + (config.getint('output') & (config.OUT_MKT_EDDN | config.OUT_SYS_EDDN | config.OUT_SYS_DELAY)) + ) + config.set( 'outdir', self.outdir.get().startswith('~') and join(config.home, self.outdir.get()[2:]) or self.outdir.get() @@ -838,6 +884,7 @@ class PreferencesDialog(tk.Toplevel): logdir = self.logdir.get() if config.default_journal_dir and logdir.lower() == config.default_journal_dir.lower(): config.set('journaldir', '') # default location + else: config.set('journaldir', logdir) @@ -846,6 +893,7 @@ class PreferencesDialog(tk.Toplevel): config.set('hotkey_mods', self.hotkey_mods) config.set('hotkey_always', int(not self.hotkey_only.get())) config.set('hotkey_mute', int(not self.hotkey_play.get())) + config.set('shipyard_provider', self.shipyard_provider.get()) config.set('system_provider', self.system_provider.get()) config.set('station_provider', self.station_provider.get()) @@ -866,6 +914,7 @@ class PreferencesDialog(tk.Toplevel): # Notify if self.callback: self.callback() + plug.notify_prefs_changed(monitor.cmdr, monitor.is_beta) self._destroy() @@ -874,6 +923,7 @@ class PreferencesDialog(tk.Toplevel): if self.cmdrchanged_alarm is not None: self.after_cancel(self.cmdrchanged_alarm) self.cmdrchanged_alarm = None + self.parent.wm_attributes('-topmost', config.getint('always_ontop') and 1 or 0) self.destroy() @@ -891,6 +941,8 @@ class PreferencesDialog(tk.Toplevel): anchor = [x for x in pane.anchors() if x.name() == 'Privacy_Accessibility'][0] anchor.reveal() prefs.activate() + except Exception: AXIsProcessTrustedWithOptions({kAXTrustedCheckOptionPrompt: True}) + self.parent.event_generate('<>', when="tail") From df554ec8b3ba6ccaaa9ac02dbd4c17413abce21d Mon Sep 17 00:00:00 2001 From: A_D Date: Sat, 12 Sep 2020 14:23:50 +0200 Subject: [PATCH 09/17] Added docstrings --- prefs.py | 116 +++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 91 insertions(+), 25 deletions(-) diff --git a/prefs.py b/prefs.py index f9b641a3..baa95363 100644 --- a/prefs.py +++ b/prefs.py @@ -1,4 +1,6 @@ # -*- coding: utf-8 -*- +"""EDMC preferences library.""" + import logging import tkinter as tk import webbrowser @@ -6,7 +8,7 @@ from os.path import exists, expanduser, expandvars, join, normpath from sys import platform from tkinter import colorchooser as tkColorChooser # type: ignore from tkinter import ttk -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, Any, Callable, Optional import myNotebook as nb import plug @@ -24,6 +26,8 @@ if TYPE_CHECKING: def _(x: str) -> str: return x +# TODO: Decouple this from platform as far as possible + ########################################################################### # Versioned preferences, so we know whether to set an 'on' default on # 'new' preferences, or not. @@ -33,6 +37,12 @@ if TYPE_CHECKING: class PrefsVersion: + """ + PrefsVersion contains versioned preferences. + + It allows new defaults to be set as they are added if they are found to be missing + """ + versions = { '0.0.0.0': 1, '1.0.0.0': 2, @@ -47,7 +57,7 @@ class PrefsVersion: def __init__(self): return - def stringToSerial(self, versionStr: str) -> int: + def stringToSerial(self, versionStr: str) -> int: # noqa: N802 # used in plugins """ Convert a version string into a preferences version serial number. @@ -66,7 +76,15 @@ class PrefsVersion: # # config.get('PrefsVersion') is the version preferences we last saved for ########################################################################### - def shouldSetDefaults(self, addedAfter: str, oldTest: bool = True) -> bool: + def shouldSetDefaults(self, addedAfter: str, oldTest: bool = True) -> bool: # noqa: N802,N803 # used in plugins + """ + Whether or not defaults should be set if they were added after the specified version. + + :param addedAfter: The version after which these settings were added + :param oldTest: Default, if we have no current settings version, defaults to True + :raises ValueError: on serial number after the current latest + :return: bool indicating the answer + """ pv = config.getint('PrefsVersion') # If no PrefsVersion yet exists then return oldTest if not pv: @@ -81,7 +99,7 @@ class PrefsVersion: aa = self.versions[addedAfter] # Sanity check, if something was added after then current should be greater if aa >= self.versions['current']: - raise Exception( + raise ValueError( 'ERROR: Call to prefs.py:PrefsVersion.shouldSetDefaults() with ' '"addedAfter" >= current latest in "versions" table.' ' You probably need to increase "current" serial number.' @@ -95,7 +113,7 @@ class PrefsVersion: ########################################################################### -prefsVersion = PrefsVersion() +prefsVersion = PrefsVersion() # noqa: N816 # Cannot rename as used in plugins ########################################################################### if platform == 'darwin': @@ -143,6 +161,13 @@ elif platform == 'win32': BrowseCallbackProc = ctypes.WINFUNCTYPE(ctypes.c_int, HWND, ctypes.c_uint, LPARAM, LPARAM) class BROWSEINFO(ctypes.Structure): + """ + BROWSEINFO class for use in calls to win32 file browser invocation. + + See https://docs.microsoft.com/en-us/windows/win32/api/shlobj_core/ns-shlobj_core-browseinfoa for more + information regarding this structure + """ + _fields_ = [ ("hwndOwner", HWND), ("pidlRoot", LPVOID), @@ -174,7 +199,9 @@ elif platform == 'win32': class PreferencesDialog(tk.Toplevel): - def __init__(self, parent, callback): + """The EDMC preferences dialog.""" + + def __init__(self, parent: tk.Tk, callback: Optional[Callable]): tk.Toplevel.__init__(self, parent) self.parent = parent @@ -200,7 +227,7 @@ class PreferencesDialog(tk.Toplevel): self.cmdr = False # Note if Cmdr changes in the Journal self.is_beta = False # Note if Beta status changes in the Journal - self.cmdrchanged_alarm = None + self.cmdrchanged_alarm: Optional[str] = None # This stores an ID that can be used to cancel a scheduled call frame = ttk.Frame(self) frame.grid(sticky=tk.NSEW) @@ -329,6 +356,7 @@ class PreferencesDialog(tk.Toplevel): _('Keyboard shortcut') or # Hotkey/Shortcut settings prompt on OSX _('Hotkey') # Hotkey/Shortcut settings prompt on Windows ).grid(row=20, padx=PADX, sticky=tk.W) + if platform == 'darwin' and not was_accessible_at_launch: if AXIsProcessTrusted(): nb.Label(configframe, text=_('Re-start {APP} to use shortcuts').format(APP=applongname), @@ -343,6 +371,7 @@ class PreferencesDialog(tk.Toplevel): ), foreground='firebrick' ).grid(columnspan=4, padx=PADX, sticky=tk.W) + nb.Button(configframe, text=_('Open System Preferences'), command=self.enableshortcuts).grid( padx=PADX, sticky=tk.E) # Shortcut settings button on OSX @@ -692,6 +721,11 @@ class PreferencesDialog(tk.Toplevel): self.geometry("+{position.left}+{position.top}") def cmdrchanged(self, event=None): + """ + Notify plugins of cmdr change. + + :param event: Unused, defaults to None + """ if self.cmdr != monitor.cmdr or self.is_beta != monitor.is_beta: # Cmdr has changed - update settings if self.cmdr is not False: # Don't notify on first run @@ -703,7 +737,7 @@ class PreferencesDialog(tk.Toplevel): # Poll self.cmdrchanged_alarm = self.after(1000, self.cmdrchanged) - def tabchanged(self, event): + def tabchanged(self, event: tk.Event) -> None: self.outvarchanged() if platform == 'darwin': # Hack to recompute size so that buttons show up under Mojave @@ -714,7 +748,7 @@ class PreferencesDialog(tk.Toplevel): temp.update_idletasks() temp.destroy() - def outvarchanged(self, event=None): + def outvarchanged(self, event: Optional[tk.Event] = None) -> None: self.displaypath(self.outdir, self.outdir_entry) self.displaypath(self.logdir, self.logdir_entry) @@ -733,6 +767,12 @@ class PreferencesDialog(tk.Toplevel): self.outdir_entry['state'] = local and 'readonly' or tk.DISABLED def filebrowse(self, title, pathvar): + """ + Open a directory selection dialog. + + :param title: Title of the window + :param pathvar: the path to start the dialog on + """ import tkinter.filedialog d = tkinter.filedialog.askdirectory( parent=self, @@ -745,7 +785,14 @@ class PreferencesDialog(tk.Toplevel): pathvar.set(d) self.outvarchanged() - def displaypath(self, pathvar, entryfield): + def displaypath(self, pathvar: tk.StringVar, entryfield: tk.Entry) -> None: + """ + Display a path in a locked tk.Entry. + + :param pathvar: the path to display + :param entryfield: the entry in which to display the path + """ + # TODO: This is awful. entryfield['state'] = tk.NORMAL # must be writable to update entryfield.delete(0, tk.END) if platform == 'win32': @@ -754,7 +801,7 @@ class PreferencesDialog(tk.Toplevel): components = normpath(pathvar.get()).split('\\') buf = ctypes.create_unicode_buffer(MAX_PATH) pidsRes = ctypes.c_int() - for i in range(start, len(components)): # TODO: enumerate + for i in range(start, len(components)): try: if (not SHGetLocalizedName('\\'.join(components[:i+1]), buf, MAX_PATH, ctypes.byref(pidsRes)) and LoadString(ctypes.WinDLL(expandvars(buf.value))._handle, pidsRes.value, buf, MAX_PATH)): @@ -766,7 +813,7 @@ class PreferencesDialog(tk.Toplevel): except Exception: display.append(components[i]) - entryfield.insert(0, '\\'.join(display)) # TODO raw string + entryfield.insert(0, '\\'.join(display)) # None if path doesn't exist elif platform == 'darwin' and NSFileManager.defaultManager().componentsToDisplayForPath_(pathvar.get()): @@ -788,21 +835,29 @@ class PreferencesDialog(tk.Toplevel): entryfield['state'] = 'readonly' - def logdir_reset(self): + def logdir_reset(self) -> None: + """Reset the log dir to the default.""" if config.default_journal_dir: self.logdir.set(config.default_journal_dir) self.outvarchanged() - def disable_autoappupdatecheckingame_changed(self): + def disable_autoappupdatecheckingame_changed(self) -> None: + """Save out the auto update check in game config.""" config.set('disable_autoappupdatecheckingame', self.disable_autoappupdatecheckingame.get()) # If it's now False, re-enable WinSparkle ? Need access to the AppWindow.updater variable to call down - def alt_shipyard_open_changed(self): + def alt_shipyard_open_changed(self) -> None: + """Save out the status of the alt shipyard config.""" config.set('use_alt_shipyard_open', self.alt_shipyard_open.get()) - def themecolorbrowse(self, index): - (rgb, color) = tkColorChooser.askcolor( + def themecolorbrowse(self, index: int) -> None: + """ + Show a color browser. + + :param index: Index of the color type, 0 for dark text, 1 for dark highlight + """ + (_, color) = tkColorChooser.askcolor( self.theme_colors[index], title=self.theme_prompts[index], parent=self.parent ) @@ -810,7 +865,8 @@ class PreferencesDialog(tk.Toplevel): self.theme_colors[index] = color self.themevarchanged() - def themevarchanged(self): + def themevarchanged(self) -> None: + """Update theme examples.""" self.theme_button_0['foreground'], self.theme_button_1['foreground'] = self.theme_colors state = self.theme.get() and tk.NORMAL or tk.DISABLED @@ -819,13 +875,15 @@ class PreferencesDialog(tk.Toplevel): self.theme_button_0['state'] = state self.theme_button_1['state'] = state - def hotkeystart(self, event): + def hotkeystart(self, event: 'tk.Event[Any]') -> None: + """Start listening for hotkeys.""" event.widget.bind('', self.hotkeylisten) event.widget.bind('', self.hotkeylisten) event.widget.delete(0, tk.END) hotkeymgr.acquire_start() - def hotkeyend(self, event): + def hotkeyend(self, event: 'tk.Event[Any]') -> None: + """Stop listening for hotkeys.""" event.widget.unbind('') event.widget.unbind('') hotkeymgr.acquire_stop() # in case focus was lost while in the middle of acquiring @@ -833,7 +891,13 @@ class PreferencesDialog(tk.Toplevel): self.hotkey_text.insert(0, self.hotkey_code and hotkeymgr.display( self.hotkey_code, self.hotkey_mods) or _('None')) # No hotkey/shortcut currently defined - def hotkeylisten(self, event): + def hotkeylisten(self, event: 'tk.Event[Any]') -> str: + """ + Hotkey handler. + + :param event: tkinter event for the hotkey + :return: "break" as a literal, to halt processing + """ good = hotkeymgr.fromevent(event) if good: (hotkey_code, hotkey_mods) = good @@ -863,9 +927,10 @@ class PreferencesDialog(tk.Toplevel): self.hotkey_only_btn.focus() # move to next widget - calls hotkeyend() implicitly - return('break') # stops further processing - insertion, Tab traversal etc + return 'break' # stops further processing - insertion, Tab traversal etc - def apply(self): + def apply(self) -> None: + """Update the config with the options set on the dialog.""" config.set('PrefsVersion', prefsVersion.stringToSerial(appversion)) config.set( 'output', @@ -919,7 +984,8 @@ class PreferencesDialog(tk.Toplevel): self._destroy() - def _destroy(self): + def _destroy(self) -> None: + """widget.destroy wrapper that does some extra cleanup.""" if self.cmdrchanged_alarm is not None: self.after_cancel(self.cmdrchanged_alarm) self.cmdrchanged_alarm = None @@ -928,7 +994,7 @@ class PreferencesDialog(tk.Toplevel): self.destroy() if platform == 'darwin': - def enableshortcuts(self): + def enableshortcuts(self) -> None: self.apply() # popup System Preferences dialog try: From f9f6907a2c8d88f8abf8f431ed40c9fdb72c309c Mon Sep 17 00:00:00 2001 From: A_D Date: Sat, 12 Sep 2020 18:05:11 +0200 Subject: [PATCH 10/17] renamed variables to reduce ambiguity --- prefs.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/prefs.py b/prefs.py index baa95363..8bf7ecc4 100644 --- a/prefs.py +++ b/prefs.py @@ -495,7 +495,7 @@ class PreferencesDialog(tk.Toplevel): current_loglevel = logging.getLevelName(logging.INFO) self.select_loglevel = tk.StringVar(value=str(current_loglevel)) loglevels = [ - logging.getLevelName(l) for l in ( + logging.getLevelName(level) for level in ( logging.CRITICAL, logging.ERROR, logging.WARNING, logging.INFO, logging.DEBUG ) ] @@ -781,8 +781,8 @@ class PreferencesDialog(tk.Toplevel): mustexist=tk.TRUE ) - if d: - pathvar.set(d) + if directory: + pathvar.set(directory) self.outvarchanged() def displaypath(self, pathvar: tk.StringVar, entryfield: tk.Entry) -> None: From fc431e457d85651d2df3ee804d18ce8e4f6c754b Mon Sep 17 00:00:00 2001 From: A_D Date: Sun, 13 Sep 2020 05:44:26 +0200 Subject: [PATCH 11/17] refactored logic --- prefs.py | 94 +++++++++++++++++++++++++++++--------------------------- 1 file changed, 49 insertions(+), 45 deletions(-) diff --git a/prefs.py b/prefs.py index 8bf7ecc4..ef3c4646 100644 --- a/prefs.py +++ b/prefs.py @@ -8,7 +8,7 @@ from os.path import exists, expanduser, expandvars, join, normpath from sys import platform from tkinter import colorchooser as tkColorChooser # type: ignore from tkinter import ttk -from typing import TYPE_CHECKING, Any, Callable, Optional +from typing import TYPE_CHECKING, Any, Callable, Optional, Union import myNotebook as nb import plug @@ -202,17 +202,19 @@ class PreferencesDialog(tk.Toplevel): """The EDMC preferences dialog.""" def __init__(self, parent: tk.Tk, callback: Optional[Callable]): + # TODO: Ive read books shorter than this method. tk.Toplevel.__init__(self, parent) self.parent = parent self.callback = callback - self.title(platform == 'darwin' and _('Preferences') or _('Settings')) + self.title(_('Preferences') if platform == 'darwin' else _('Settings')) if parent.winfo_viewable(): self.transient(parent) # position over parent if platform != 'darwin' or parent.winfo_rooty() > 0: # http://core.tcl.tk/tk/tktview/c84f660833546b1b84e7 + # TODO this is fixed supposedly. self.geometry(f'+{parent.winfo_rootx()}+{parent.winfo_rooty()}') # remove decoration @@ -225,8 +227,8 @@ class PreferencesDialog(tk.Toplevel): self.resizable(tk.FALSE, tk.FALSE) - self.cmdr = False # Note if Cmdr changes in the Journal - self.is_beta = False # Note if Beta status changes in the Journal + self.cmdr: Union[str, bool, None] = False # Note if Cmdr changes in the Journal + self.is_beta: bool = False # Note if Beta status changes in the Journal self.cmdrchanged_alarm: Optional[str] = None # This stores an ID that can be used to cancel a scheduled call frame = ttk.Frame(self) @@ -253,7 +255,7 @@ class PreferencesDialog(tk.Toplevel): # the middle without worrying about updating `row=X` elements. self.out_label = nb.Label(outframe, text=_('Please choose what data to save')) self.out_label.grid(columnspan=2, padx=PADX, sticky=tk.W) - self.out_csv = tk.IntVar(value=(output & config.OUT_MKT_CSV) and 1) + self.out_csv = tk.IntVar(value=1 if (output & config.OUT_MKT_CSV) else 0) self.out_csv_button = nb.Checkbutton( outframe, text=_('Market data in CSV format file'), @@ -262,7 +264,7 @@ class PreferencesDialog(tk.Toplevel): ) self.out_csv_button.grid(columnspan=2, padx=BUTTONX, sticky=tk.W) - self.out_td = tk.IntVar(value=(output & config.OUT_MKT_TD) and 1) + self.out_td = tk.IntVar(value=1 if (output & config.OUT_MKT_TD) else 0) self.out_td_button = nb.Checkbutton( outframe, text=_('Market data in Trade Dangerous format file'), @@ -271,7 +273,7 @@ class PreferencesDialog(tk.Toplevel): ) self.out_td_button.grid(columnspan=2, padx=BUTTONX, sticky=tk.W) - self.out_ship = tk.IntVar(value=(output & config.OUT_SHIP and 1)) + self.out_ship = tk.IntVar(value=1 if (output & config.OUT_SHIP) else 0) # Output setting self.out_ship_button = nb.Checkbutton( @@ -301,7 +303,7 @@ class PreferencesDialog(tk.Toplevel): self.outdir_entry.grid(columnspan=2, padx=PADX, pady=(0, PADY), sticky=tk.EW) self.outbutton = nb.Button( outframe, - text=(platform == 'darwin' and _('Change...') or _('Browse...')), + text=(_('Change...') if platform == 'darwin' else _('Browse...')), command=lambda: self.filebrowse(_('File location'), self.outdir) ) @@ -332,7 +334,7 @@ class PreferencesDialog(tk.Toplevel): self.logdir_entry.grid(columnspan=4, padx=PADX, pady=(0, PADY), sticky=tk.EW) self.logbutton = nb.Button( configframe, - text=(platform == 'darwin' and _('Change...') or _('Browse...')), + text=(_('Change...') if platform == 'darwin' else _('Browse...')), command=lambda: self.filebrowse(_('E:D journal file location'), self.logdir) ) @@ -343,7 +345,7 @@ class PreferencesDialog(tk.Toplevel): configframe, text=_('Default'), command=self.logdir_reset, - state=config.get('journaldir') and tk.NORMAL or tk.DISABLED + state=tk.NORMAL if config.get('journaldir') else tk.DISABLED ).grid(row=10, column=2, pady=PADY, sticky=tk.EW) if platform in ['darwin', 'win32']: @@ -352,10 +354,12 @@ class PreferencesDialog(tk.Toplevel): self.hotkey_mods = config.getint('hotkey_mods') self.hotkey_only = tk.IntVar(value=not config.getint('hotkey_always')) self.hotkey_play = tk.IntVar(value=not config.getint('hotkey_mute')) - nb.Label(configframe, text=platform == 'darwin' and - _('Keyboard shortcut') or # Hotkey/Shortcut settings prompt on OSX - _('Hotkey') # Hotkey/Shortcut settings prompt on Windows - ).grid(row=20, padx=PADX, sticky=tk.W) + nb.Label( + configframe, + text=_('Keyboard shortcut') if # Hotkey/Shortcut settings prompt on OSX + platform == 'darwin' else + _('Hotkey') # Hotkey/Shortcut settings prompt on Windows + ).grid(row=20, padx=PADX, sticky=tk.W) if platform == 'darwin' and not was_accessible_at_launch: if AXIsProcessTrusted(): @@ -376,13 +380,12 @@ class PreferencesDialog(tk.Toplevel): padx=PADX, sticky=tk.E) # Shortcut settings button on OSX else: - self.hotkey_text = nb.Entry(configframe, width=(platform == 'darwin' and 20 or 30), justify=tk.CENTER) + self.hotkey_text = nb.Entry(configframe, width=(20 if platform == 'darwin' else 30), justify=tk.CENTER) self.hotkey_text.insert( 0, # No hotkey/shortcut currently defined - self.hotkey_code and hotkeymgr.display( # type: ignore # Only shows up on darwin or windows - self.hotkey_code, self.hotkey_mods - ) or _('None') + # TODO: display Only shows up on darwin or windows + hotkeymgr.display(self.hotkey_code, self.hotkey_mods) if self.hotkey_code else _('None') ) self.hotkey_text.bind('', self.hotkeystart) @@ -394,7 +397,7 @@ class PreferencesDialog(tk.Toplevel): configframe, text=_('Only when Elite: Dangerous is the active app'), variable=self.hotkey_only, - state=self.hotkey_code and tk.NORMAL or tk.DISABLED + state=tk.NORMAL if self.hotkey_code else tk.DISABLED ) self.hotkey_only_btn.grid(columnspan=4, padx=PADX, pady=(5, 0), sticky=tk.W) @@ -404,7 +407,7 @@ class PreferencesDialog(tk.Toplevel): configframe, text=_('Play sound'), variable=self.hotkey_play, - state=self.hotkey_code and tk.NORMAL or tk.DISABLED + state=tk.NORMAL if self.hotkey_code else tk.DISABLED ) self.hotkey_play_btn.grid(columnspan=4, padx=PADX, sticky=tk.W) @@ -449,9 +452,9 @@ class PreferencesDialog(tk.Toplevel): self.alt_shipyard_open_btn.grid(row=31, column=2, sticky=tk.W) + system_provider = config.get('system_provider') self.system_provider = tk.StringVar( - value=str(config.get('system_provider') in plug.provides('system_url') - and config.get('system_provider') or 'EDSM') + value=str(system_provider if system_provider in plug.provides('system_url') else 'EDSM') ) nb.Label(configframe, text=_('System')).grid(row=32, padx=PADX, pady=2*PADY, sticky=tk.W) @@ -465,9 +468,9 @@ class PreferencesDialog(tk.Toplevel): self.system_button.configure(width=15) self.system_button.grid(row=32, column=1, sticky=tk.W) + station_provider = config.get('station_provider') self.station_provider = tk.StringVar( - value=str(config.get('station_provider') in plug.provides('station_url') - and config.get('station_provider') or 'eddb') + value=str(station_provider if station_provider in plug.provides('station_url') else 'eddb') ) nb.Label(configframe, text=_('Station')).grid(row=33, padx=PADX, pady=2*PADY, sticky=tk.W) @@ -494,11 +497,9 @@ class PreferencesDialog(tk.Toplevel): if not current_loglevel: current_loglevel = logging.getLevelName(logging.INFO) self.select_loglevel = tk.StringVar(value=str(current_loglevel)) - loglevels = [ - logging.getLevelName(level) for level in ( - logging.CRITICAL, logging.ERROR, logging.WARNING, logging.INFO, logging.DEBUG - ) - ] + loglevels = list( + map(logging.getLevelName, (logging.CRITICAL, logging.ERROR, logging.WARNING, logging.INFO, logging.DEBUG)) + ) self.loglevel_dropdown = nb.OptionMenu( configframe, @@ -635,7 +636,7 @@ class PreferencesDialog(tk.Toplevel): text=_("Tip: You can disable a plugin by{CR}adding '{EXT}' to its folder name").format(EXT='.disabled') ).grid(columnspan=2, padx=PADX, pady=10, sticky=tk.NSEW) - enabled_plugins = [x for x in plug.PLUGINS if x.folder and x.module] + enabled_plugins = list(filter(lambda x: x.folder and x.module, plug.PLUGINS)) if len(enabled_plugins): ttk.Separator(plugsframe, orient=tk.HORIZONTAL).grid(columnspan=3, padx=PADX, pady=PADY * 8, sticky=tk.EW) nb.Label( @@ -649,6 +650,7 @@ class PreferencesDialog(tk.Toplevel): else: label = nb.Label(plugsframe, text=f'{plugin.folder} ({plugin.name})') + label.grid(columnspan=2, padx=PADX*2, sticky=tk.W) ############################################################ @@ -670,7 +672,7 @@ class PreferencesDialog(tk.Toplevel): ).grid(columnspan=2, padx=PADX, sticky=tk.W) ############################################################ - disabled_plugins = [x for x in plug.PLUGINS if x.folder and not x.module] + disabled_plugins = list(filter(lambda x: x.folder and not x.module, plug.PLUGINS)) if len(disabled_plugins): ttk.Separator(plugsframe, orient=tk.HORIZONTAL).grid(columnspan=3, padx=PADX, pady=PADY * 8, sticky=tk.EW) nb.Label( @@ -753,18 +755,18 @@ class PreferencesDialog(tk.Toplevel): self.displaypath(self.logdir, self.logdir_entry) logdir = self.logdir.get() - logvalid = logdir and exists(logdir) + logvalid = exists(logdir) if logdir else False self.out_label['state'] = tk.NORMAL self.out_csv_button['state'] = tk.NORMAL self.out_td_button['state'] = tk.NORMAL self.out_ship_button['state'] = tk.NORMAL - local = self.out_td.get() or self.out_csv.get() or self.out_ship.get() - self.out_auto_button['state'] = local and logvalid and tk.NORMAL or tk.DISABLED - self.outdir_label['state'] = local and tk.NORMAL or tk.DISABLED - self.outbutton['state'] = local and tk.NORMAL or tk.DISABLED - self.outdir_entry['state'] = local and 'readonly' or tk.DISABLED + local = any((self.out_td.get(), self.out_csv.get(), self.out_ship.get())) + self.out_auto_button['state'] = tk.NORMAL if local and logvalid else tk.DISABLED + self.outdir_label['state'] = tk.NORMAL if local else tk.DISABLED + self.outbutton['state'] = tk.NORMAL if local else tk.DISABLED + self.outdir_entry['state'] = tk.NORMAL if local else tk.DISABLED def filebrowse(self, title, pathvar): """ @@ -774,7 +776,7 @@ class PreferencesDialog(tk.Toplevel): :param pathvar: the path to start the dialog on """ import tkinter.filedialog - d = tkinter.filedialog.askdirectory( + directory = tkinter.filedialog.askdirectory( parent=self, initialdir=expanduser(pathvar.get()), title=title, @@ -796,7 +798,7 @@ class PreferencesDialog(tk.Toplevel): entryfield['state'] = tk.NORMAL # must be writable to update entryfield.delete(0, tk.END) if platform == 'win32': - start = pathvar.get().lower().startswith(config.home.lower()) and len(config.home.split('\\')) or 0 + start = len(config.home.split('\\')) if pathvar.get().lower().startswith(config.home.lower()) else 0 display = [] components = normpath(pathvar.get()).split('\\') buf = ctypes.create_unicode_buffer(MAX_PATH) @@ -869,7 +871,7 @@ class PreferencesDialog(tk.Toplevel): """Update theme examples.""" self.theme_button_0['foreground'], self.theme_button_1['foreground'] = self.theme_colors - state = self.theme.get() and tk.NORMAL or tk.DISABLED + state = tk.NORMAL if self.theme.get() else tk.DISABLED self.theme_label_0['state'] = state self.theme_label_1['state'] = state self.theme_button_0['state'] = state @@ -888,8 +890,10 @@ class PreferencesDialog(tk.Toplevel): event.widget.unbind('') hotkeymgr.acquire_stop() # in case focus was lost while in the middle of acquiring event.widget.delete(0, tk.END) - self.hotkey_text.insert(0, self.hotkey_code and hotkeymgr.display( - self.hotkey_code, self.hotkey_mods) or _('None')) # No hotkey/shortcut currently defined + self.hotkey_text.insert( + 0, + # No hotkey/shortcut currently defined + hotkeymgr.display(self.hotkey_code, self.hotkey_mods) if self.hotkey_code else _('None')) def hotkeylisten(self, event: 'tk.Event[Any]') -> str: """ @@ -943,7 +947,7 @@ class PreferencesDialog(tk.Toplevel): config.set( 'outdir', - self.outdir.get().startswith('~') and join(config.home, self.outdir.get()[2:]) or self.outdir.get() + join(config.home, self.outdir.get()[2:]) if self.outdir.get().startswith('~') else self.outdir.get() ) logdir = self.logdir.get() @@ -966,7 +970,7 @@ class PreferencesDialog(tk.Toplevel): edmclogger.get_streamhandler().setLevel(self.select_loglevel.get()) lang_codes = {v: k for k, v in self.languages.items()} # Codes by name - config.set('language', lang_codes.get(self.lang.get()) or '') + config.set('language', lang_codes.get(self.lang.get()) or '') # or '' used here due to Default being None above Translations.install(config.get('language') or None) # type: ignore # This sets self in weird ways. config.set('ui_scale', self.ui_scale.get()) @@ -990,7 +994,7 @@ class PreferencesDialog(tk.Toplevel): self.after_cancel(self.cmdrchanged_alarm) self.cmdrchanged_alarm = None - self.parent.wm_attributes('-topmost', config.getint('always_ontop') and 1 or 0) + self.parent.wm_attributes('-topmost', 1 if config.getint('always_ontop') else 0) self.destroy() if platform == 'darwin': From 871838106f820884c369ef73c3eaa0be9a84aa48 Mon Sep 17 00:00:00 2001 From: A_D Date: Mon, 14 Sep 2020 15:51:51 +0200 Subject: [PATCH 12/17] Broke __init__ into multiple methods Each tab now has its own method, rather than them all being in one giant unmaintainable blob in the middle of the init method --- prefs.py | 243 +++++++++++++++++++++++++++++++------------------------ 1 file changed, 138 insertions(+), 105 deletions(-) diff --git a/prefs.py b/prefs.py index ef3c4646..ba675080 100644 --- a/prefs.py +++ b/prefs.py @@ -6,11 +6,12 @@ import tkinter as tk import webbrowser from os.path import exists, expanduser, expandvars, join, normpath from sys import platform -from tkinter import colorchooser as tkColorChooser # type: ignore +from tkinter import Variable, colorchooser as tkColorChooser # type: ignore from tkinter import ttk from typing import TYPE_CHECKING, Any, Callable, Optional, Union import myNotebook as nb +from myNotebook import Notebook import plug from config import applongname, appname, appversion, config from EDMCLogging import edmclogger @@ -202,7 +203,6 @@ class PreferencesDialog(tk.Toplevel): """The EDMC preferences dialog.""" def __init__(self, parent: tk.Tk, callback: Optional[Callable]): - # TODO: Ive read books shorter than this method. tk.Toplevel.__init__(self, parent) self.parent = parent @@ -237,11 +237,57 @@ class PreferencesDialog(tk.Toplevel): notebook = nb.Notebook(frame) notebook.bind('<>', self.tabchanged) # Recompute on tab change - PADX = 10 - BUTTONX = 12 # indent Checkbuttons and Radiobuttons - PADY = 2 # close spacing + self.PADX = 10 + self.BUTTONX = 12 # indent Checkbuttons and Radiobuttons + self.PADY = 2 # close spacing - outframe = nb.Frame(notebook) + # Set up different tabs + # TODO: modify these to be "__create_$tab_tab" and have them return the frame rather than set it up themselves + self.__setup_output_tab(notebook) + self.__setup_plugin_tabs(notebook) + self.__setup_config_tab(notebook) + self.__setup_theme_tab(notebook) + self.__setup_plugin_tab(notebook) + + if platform == 'darwin': + self.protocol("WM_DELETE_WINDOW", self.apply) # close button applies changes + + else: + buttonframe = ttk.Frame(frame) + buttonframe.grid(padx=self.PADX, pady=self.PADX, sticky=tk.NSEW) + buttonframe.columnconfigure(0, weight=1) + ttk.Label(buttonframe).grid(row=0, column=0) # spacer + button = ttk.Button(buttonframe, text=_('OK'), command=self.apply) + button.grid(row=0, column=1, sticky=tk.E) + button.bind("", lambda event: self.apply()) + self.protocol("WM_DELETE_WINDOW", self._destroy) + + # Selectively disable buttons depending on output settings + self.cmdrchanged() + self.themevarchanged() + + # disable hotkey for the duration + hotkeymgr.unregister() + + # wait for window to appear on screen before calling grab_set + self.parent.update_idletasks() + self.parent.wm_attributes('-topmost', 0) # needed for dialog to appear ontop of parent on OSX & Linux + self.wait_visibility() + self.grab_set() + + # Ensure fully on-screen + if platform == 'win32' and CalculatePopupWindowPosition: + position = RECT() + GetWindowRect(GetParent(self.winfo_id()), position) + if CalculatePopupWindowPosition( + POINT(parent.winfo_rootx(), parent.winfo_rooty()), + SIZE(position.right - position.left, position.bottom - position.top), + 0x10000, None, position + ): + self.geometry(f"+{position.left}+{position.top}") + + def __setup_output_tab(self, root_notebook: nb.Notebook) -> None: + outframe = nb.Frame(root_notebook) outframe.columnconfigure(0, weight=1) if prefsVersion.shouldSetDefaults('0.0.0.0', not bool(config.getint('output'))): @@ -250,11 +296,16 @@ class PreferencesDialog(tk.Toplevel): else: output = config.getint('output') + row = 0 + # TODO: *All* of this needs to use a 'row' variable, incremented after # adding one to keep track, so it's easier to insert new rows in # the middle without worrying about updating `row=X` elements. self.out_label = nb.Label(outframe, text=_('Please choose what data to save')) - self.out_label.grid(columnspan=2, padx=PADX, sticky=tk.W) + self.out_label.grid(columnspan=2, padx=self.PADX, sticky=tk.W, row=row) + + row += 1 + self.out_csv = tk.IntVar(value=1 if (output & config.OUT_MKT_CSV) else 0) self.out_csv_button = nb.Checkbutton( outframe, @@ -262,8 +313,10 @@ class PreferencesDialog(tk.Toplevel): variable=self.out_csv, command=self.outvarchanged ) + self.out_csv_button.grid(columnspan=2, padx=self.BUTTONX, sticky=tk.W, row=row) + + row += 1 - self.out_csv_button.grid(columnspan=2, padx=BUTTONX, sticky=tk.W) self.out_td = tk.IntVar(value=1 if (output & config.OUT_MKT_TD) else 0) self.out_td_button = nb.Checkbutton( outframe, @@ -271,10 +324,11 @@ class PreferencesDialog(tk.Toplevel): variable=self.out_td, command=self.outvarchanged ) - - self.out_td_button.grid(columnspan=2, padx=BUTTONX, sticky=tk.W) + self.out_td_button.grid(columnspan=2, padx=self.BUTTONX, sticky=tk.W, row=row) self.out_ship = tk.IntVar(value=1 if (output & config.OUT_SHIP) else 0) + row += 1 + # Output setting self.out_ship_button = nb.Checkbutton( outframe, @@ -282,9 +336,11 @@ class PreferencesDialog(tk.Toplevel): variable=self.out_ship, command=self.outvarchanged ) - self.out_ship_button.grid(columnspan=2, padx=BUTTONX, pady=(5, 0), sticky=tk.W) + self.out_ship_button.grid(columnspan=2, padx=self.BUTTONX, pady=(5, 0), sticky=tk.W, row=row) self.out_auto = tk.IntVar(value=0 if output & config.OUT_MKT_MANUAL else 1) # inverted + row += 1 + # Output setting self.out_auto_button = nb.Checkbutton( outframe, @@ -292,32 +348,42 @@ class PreferencesDialog(tk.Toplevel): variable=self.out_auto, command=self.outvarchanged ) + self.out_auto_button.grid(columnspan=2, padx=self.BUTTONX, pady=(5, 0), sticky=tk.W, row=row) - self.out_auto_button.grid(columnspan=2, padx=BUTTONX, pady=(5, 0), sticky=tk.W) + row += 1 self.outdir = tk.StringVar() self.outdir.set(str(config.get('outdir'))) self.outdir_label = nb.Label(outframe, text=_('File location')+':') # Section heading in settings - self.outdir_label.grid(padx=PADX, pady=(5, 0), sticky=tk.W) # type: ignore # 2 tuple does each side + self.outdir_label.grid(padx=self.PADX, pady=(5, 0), sticky=tk.W, row=row) # type: ignore # 2 tuple, each side + + row += 1 + self.outdir_entry = nb.Entry(outframe, takefocus=False) - self.outdir_entry.grid(columnspan=2, padx=PADX, pady=(0, PADY), sticky=tk.EW) + self.outdir_entry.grid(columnspan=2, padx=self.PADX, pady=(0, self.PADY), sticky=tk.EW, row=row) + + row += 1 + self.outbutton = nb.Button( outframe, text=(_('Change...') if platform == 'darwin' else _('Browse...')), command=lambda: self.filebrowse(_('File location'), self.outdir) ) + self.outbutton.grid(column=1, padx=self.PADX, pady=self.PADY, sticky=tk.NSEW, row=row) + + row += 1 + + nb.Frame(outframe).grid(row=row) # bottom spacer # TODO: does nothing? - self.outbutton.grid(column=1, padx=PADX, pady=PADY, sticky=tk.NSEW) - nb.Frame(outframe).grid(pady=5) # bottom spacer + root_notebook.add(outframe, text=_('Output')) # Tab heading in settings - notebook.add(outframe, text=_('Output')) # Tab heading in settings - - # build plugin prefs tabs + def __setup_plugin_tabs(self, notebook: Notebook) -> None: for plugin in plug.PLUGINS: plugframe = plugin.get_prefs(notebook, monitor.cmdr, monitor.is_beta) if plugframe: notebook.add(plugframe, text=plugin.name) + def __setup_config_tab(self, notebook: Notebook) -> None: configframe = nb.Frame(notebook) configframe.columnconfigure(1, weight=1) @@ -329,16 +395,16 @@ class PreferencesDialog(tk.Toplevel): nb.Label( configframe, text=_('E:D journal file location')+':' - ).grid(columnspan=4, padx=PADX, sticky=tk.W) + ).grid(columnspan=4, padx=self.PADX, sticky=tk.W) - self.logdir_entry.grid(columnspan=4, padx=PADX, pady=(0, PADY), sticky=tk.EW) + self.logdir_entry.grid(columnspan=4, padx=self.PADX, pady=(0, self.PADY), sticky=tk.EW) self.logbutton = nb.Button( configframe, text=(_('Change...') if platform == 'darwin' else _('Browse...')), command=lambda: self.filebrowse(_('E:D journal file location'), self.logdir) ) - self.logbutton.grid(row=10, column=3, padx=PADX, pady=PADY, sticky=tk.EW) + self.logbutton.grid(row=10, column=3, padx=self.PADX, pady=self.PADY, sticky=tk.EW) if config.default_journal_dir: # Appearance theme and language setting nb.Button( @@ -346,10 +412,10 @@ class PreferencesDialog(tk.Toplevel): text=_('Default'), command=self.logdir_reset, state=tk.NORMAL if config.get('journaldir') else tk.DISABLED - ).grid(row=10, column=2, pady=PADY, sticky=tk.EW) + ).grid(row=10, column=2, pady=self.PADY, sticky=tk.EW) if platform in ['darwin', 'win32']: - ttk.Separator(configframe, orient=tk.HORIZONTAL).grid(columnspan=4, padx=PADX, pady=PADY*4, sticky=tk.EW) + ttk.Separator(configframe, orient=tk.HORIZONTAL).grid(columnspan=4, padx=self.PADX, pady=self.PADY*4, sticky=tk.EW) self.hotkey_code = config.getint('hotkey_code') self.hotkey_mods = config.getint('hotkey_mods') self.hotkey_only = tk.IntVar(value=not config.getint('hotkey_always')) @@ -359,12 +425,12 @@ class PreferencesDialog(tk.Toplevel): text=_('Keyboard shortcut') if # Hotkey/Shortcut settings prompt on OSX platform == 'darwin' else _('Hotkey') # Hotkey/Shortcut settings prompt on Windows - ).grid(row=20, padx=PADX, sticky=tk.W) + ).grid(row=20, padx=self.PADX, sticky=tk.W) if platform == 'darwin' and not was_accessible_at_launch: if AXIsProcessTrusted(): nb.Label(configframe, text=_('Re-start {APP} to use shortcuts').format(APP=applongname), - foreground='firebrick').grid(padx=PADX, sticky=tk.W) # Shortcut settings prompt on OSX + foreground='firebrick').grid(padx=self.PADX, sticky=tk.W) # Shortcut settings prompt on OSX else: # Shortcut settings prompt on OSX @@ -374,10 +440,10 @@ class PreferencesDialog(tk.Toplevel): APP=applongname ), foreground='firebrick' - ).grid(columnspan=4, padx=PADX, sticky=tk.W) + ).grid(columnspan=4, padx=self.PADX, sticky=tk.W) nb.Button(configframe, text=_('Open System Preferences'), command=self.enableshortcuts).grid( - padx=PADX, sticky=tk.E) # Shortcut settings button on OSX + padx=self.PADX, sticky=tk.E) # Shortcut settings button on OSX else: self.hotkey_text = nb.Entry(configframe, width=(20 if platform == 'darwin' else 30), justify=tk.CENTER) @@ -400,7 +466,7 @@ class PreferencesDialog(tk.Toplevel): state=tk.NORMAL if self.hotkey_code else tk.DISABLED ) - self.hotkey_only_btn.grid(columnspan=4, padx=PADX, pady=(5, 0), sticky=tk.W) + self.hotkey_only_btn.grid(columnspan=4, padx=self.PADX, pady=(5, 0), sticky=tk.W) # Hotkey/Shortcut setting self.hotkey_play_btn = nb.Checkbutton( @@ -410,10 +476,10 @@ class PreferencesDialog(tk.Toplevel): state=tk.NORMAL if self.hotkey_code else tk.DISABLED ) - self.hotkey_play_btn.grid(columnspan=4, padx=PADX, sticky=tk.W) + self.hotkey_play_btn.grid(columnspan=4, padx=self.PADX, sticky=tk.W) # Option to disabled Automatic Check For Updates whilst in-game - ttk.Separator(configframe, orient=tk.HORIZONTAL).grid(columnspan=4, padx=PADX, pady=PADY*4, sticky=tk.EW) + ttk.Separator(configframe, orient=tk.HORIZONTAL).grid(columnspan=4, padx=self.PADX, pady=self.PADY*4, sticky=tk.EW) self.disable_autoappupdatecheckingame = tk.IntVar(value=config.getint('disable_autoappupdatecheckingame')) self.disable_autoappupdatecheckingame_btn = nb.Checkbutton( configframe, @@ -422,11 +488,11 @@ class PreferencesDialog(tk.Toplevel): command=self.disable_autoappupdatecheckingame_changed ) - self.disable_autoappupdatecheckingame_btn.grid(columnspan=4, padx=PADX, sticky=tk.W) + self.disable_autoappupdatecheckingame_btn.grid(columnspan=4, padx=self.PADX, sticky=tk.W) - ttk.Separator(configframe, orient=tk.HORIZONTAL).grid(columnspan=4, padx=PADX, pady=PADY*4, sticky=tk.EW) + ttk.Separator(configframe, orient=tk.HORIZONTAL).grid(columnspan=4, padx=self.PADX, pady=self.PADY*4, sticky=tk.EW) # Settings prompt for preferred ship loadout, system and station info websites - nb.Label(configframe, text=_('Preferred websites')).grid(row=30, columnspan=4, padx=PADX, sticky=tk.W) + nb.Label(configframe, text=_('Preferred websites')).grid(row=30, columnspan=4, padx=self.PADX, sticky=tk.W) self.shipyard_provider = tk.StringVar( value=str( @@ -434,7 +500,7 @@ class PreferencesDialog(tk.Toplevel): and config.get('shipyard_provider') or 'EDSY') ) # Setting to decide which ship outfitting website to link to - either E:D Shipyard or Coriolis - nb.Label(configframe, text=_('Shipyard')).grid(row=31, padx=PADX, pady=2*PADY, sticky=tk.W) + nb.Label(configframe, text=_('Shipyard')).grid(row=31, padx=self.PADX, pady=2*self.PADY, sticky=tk.W) self.shipyard_button = nb.OptionMenu( configframe, self.shipyard_provider, self.shipyard_provider.get(), *plug.provides('shipyard_url') ) @@ -457,7 +523,7 @@ class PreferencesDialog(tk.Toplevel): value=str(system_provider if system_provider in plug.provides('system_url') else 'EDSM') ) - nb.Label(configframe, text=_('System')).grid(row=32, padx=PADX, pady=2*PADY, sticky=tk.W) + nb.Label(configframe, text=_('System')).grid(row=32, padx=self.PADX, pady=2*self.PADY, sticky=tk.W) self.system_button = nb.OptionMenu( configframe, self.system_provider, @@ -473,7 +539,7 @@ class PreferencesDialog(tk.Toplevel): value=str(station_provider if station_provider in plug.provides('station_url') else 'eddb') ) - nb.Label(configframe, text=_('Station')).grid(row=33, padx=PADX, pady=2*PADY, sticky=tk.W) + nb.Label(configframe, text=_('Station')).grid(row=33, padx=self.PADX, pady=2*self.PADY, sticky=tk.W) self.station_button = nb.OptionMenu( configframe, self.station_provider, @@ -485,13 +551,13 @@ class PreferencesDialog(tk.Toplevel): self.station_button.grid(row=33, column=1, sticky=tk.W) # Set loglevel - ttk.Separator(configframe, orient=tk.HORIZONTAL).grid(columnspan=4, padx=PADX, pady=PADY*4, sticky=tk.EW) + ttk.Separator(configframe, orient=tk.HORIZONTAL).grid(columnspan=4, padx=self.PADX, pady=self.PADY*4, sticky=tk.EW) # Set the current loglevel nb.Label( configframe, text=_('Log Level') - ).grid(row=35, padx=PADX, pady=2*PADY, sticky=tk.W) + ).grid(row=35, padx=self.PADX, pady=2*self.PADY, sticky=tk.W) current_loglevel = config.get('loglevel') if not current_loglevel: @@ -526,17 +592,19 @@ class PreferencesDialog(tk.Toplevel): _('Normal text'), # Dark theme color setting _('Highlighted text'), # Dark theme color setting ] + + def __setup_theme_tab(self, notebook: Notebook) -> None: themeframe = nb.Frame(notebook) themeframe.columnconfigure(2, weight=1) - nb.Label(themeframe, text=_('Language')).grid(row=10, padx=PADX, sticky=tk.W) # Appearance setting prompt + nb.Label(themeframe, text=_('Language')).grid(row=10, padx=self.PADX, sticky=tk.W) # Appearance setting prompt self.lang_button = nb.OptionMenu(themeframe, self.lang, self.lang.get(), *self.languages.values()) - self.lang_button.grid(row=10, column=1, columnspan=2, padx=PADX, sticky=tk.W) - ttk.Separator(themeframe, orient=tk.HORIZONTAL).grid(columnspan=3, padx=PADX, pady=PADY*4, sticky=tk.EW) - nb.Label(themeframe, text=_('Theme')).grid(columnspan=3, padx=PADX, sticky=tk.W) # Appearance setting + self.lang_button.grid(row=10, column=1, columnspan=2, padx=self.PADX, sticky=tk.W) + ttk.Separator(themeframe, orient=tk.HORIZONTAL).grid(columnspan=3, padx=self.PADX, pady=self.PADY*4, sticky=tk.EW) + nb.Label(themeframe, text=_('Theme')).grid(columnspan=3, padx=self.PADX, sticky=tk.W) # Appearance setting nb.Radiobutton(themeframe, text=_('Default'), variable=self.theme, value=0, command=self.themevarchanged).grid( - columnspan=3, padx=BUTTONX, sticky=tk.W) # Appearance theme and language setting + columnspan=3, padx=self.BUTTONX, sticky=tk.W) # Appearance theme and language setting nb.Radiobutton(themeframe, text=_('Dark'), variable=self.theme, value=1, command=self.themevarchanged).grid( - columnspan=3, padx=BUTTONX, sticky=tk.W) # Appearance theme setting + columnspan=3, padx=self.BUTTONX, sticky=tk.W) # Appearance theme setting if platform == 'win32': nb.Radiobutton( @@ -545,10 +613,10 @@ class PreferencesDialog(tk.Toplevel): variable=self.theme, value=2, command=self.themevarchanged - ).grid(columnspan=3, padx=BUTTONX, sticky=tk.W) + ).grid(columnspan=3, padx=self.BUTTONX, sticky=tk.W) self.theme_label_0 = nb.Label(themeframe, text=self.theme_prompts[0]) - self.theme_label_0.grid(row=20, padx=PADX, sticky=tk.W) + self.theme_label_0.grid(row=20, padx=self.PADX, sticky=tk.W) # Main window self.theme_button_0 = nb.ColoredButton( @@ -558,9 +626,9 @@ class PreferencesDialog(tk.Toplevel): command=lambda: self.themecolorbrowse(0) ) - self.theme_button_0.grid(row=20, column=1, padx=PADX, pady=PADY, sticky=tk.NSEW) + self.theme_button_0.grid(row=20, column=1, padx=self.PADX, pady=self.PADY, sticky=tk.NSEW) self.theme_label_1 = nb.Label(themeframe, text=self.theme_prompts[1]) - self.theme_label_1.grid(row=21, padx=PADX, sticky=tk.W) + self.theme_label_1.grid(row=21, padx=self.PADX, sticky=tk.W) self.theme_button_1 = nb.ColoredButton( themeframe, text=' Hutton Orbital ', # Do not translate @@ -568,7 +636,7 @@ class PreferencesDialog(tk.Toplevel): command=lambda: self.themecolorbrowse(1) ) - self.theme_button_1.grid(row=21, column=1, padx=PADX, pady=PADY, sticky=tk.NSEW) + self.theme_button_1.grid(row=21, column=1, padx=self.PADX, pady=self.PADY, sticky=tk.NSEW) # UI Scaling """ @@ -578,8 +646,8 @@ class PreferencesDialog(tk.Toplevel): So, if at startup we find tk-scaling is 1.33 and have a user setting of 200 we'll end up setting 2.66 as the tk-scaling value. """ - ttk.Separator(themeframe, orient=tk.HORIZONTAL).grid(columnspan=4, padx=PADX, pady=PADY*4, sticky=tk.EW) - nb.Label(themeframe, text=_('UI Scale Percentage')).grid(row=23, padx=PADX, pady=2*PADY, sticky=tk.W) + ttk.Separator(themeframe, orient=tk.HORIZONTAL).grid(columnspan=4, padx=self.PADX, pady=self.PADY*4, sticky=tk.EW) + nb.Label(themeframe, text=_('UI Scale Percentage')).grid(row=23, padx=self.PADX, pady=2*self.PADY, sticky=tk.W) self.ui_scale = tk.IntVar() self.ui_scale.set(config.getint('ui_scale')) self.uiscale_bar = tk.Scale( @@ -600,7 +668,7 @@ class PreferencesDialog(tk.Toplevel): ).grid(row=23, column=3, padx=PADX, pady=2*PADY, sticky=tk.E) # Always on top - ttk.Separator(themeframe, orient=tk.HORIZONTAL).grid(columnspan=3, padx=PADX, pady=PADY*4, sticky=tk.EW) + ttk.Separator(themeframe, orient=tk.HORIZONTAL).grid(columnspan=3, padx=self.PADX, pady=self.PADY*4, sticky=tk.EW) self.ontop_button = nb.Checkbutton( themeframe, text=_('Always on top'), @@ -608,41 +676,43 @@ class PreferencesDialog(tk.Toplevel): command=self.themevarchanged ) - self.ontop_button.grid(columnspan=3, padx=BUTTONX, sticky=tk.W) # Appearance setting + self.ontop_button.grid(columnspan=3, padx=self.BUTTONX, sticky=tk.W) # Appearance setting nb.Label(themeframe).grid(sticky=tk.W) # big spacer notebook.add(themeframe, text=_('Appearance')) # Tab heading in settings + def __setup_plugin_tab(self, notebook: Notebook) -> None: + # Plugin tab itself # Plugin settings and info plugsframe = nb.Frame(notebook) plugsframe.columnconfigure(0, weight=1) plugdir = tk.StringVar() plugdir.set(config.plugin_dir) - nb.Label(plugsframe, text=_('Plugins folder')+':').grid(padx=PADX, sticky=tk.W) # Section heading in settings + nb.Label(plugsframe, text=_('Plugins folder')+':').grid(padx=self.PADX, sticky=tk.W) # Section heading in settings plugdirentry = nb.Entry(plugsframe, justify=tk.LEFT) self.displaypath(plugdir, plugdirentry) - plugdirentry.grid(row=10, padx=PADX, sticky=tk.EW) + plugdirentry.grid(row=10, padx=self.PADX, sticky=tk.EW) nb.Button( plugsframe, text=_('Open'), # Button that opens a folder in Explorer/Finder command=lambda: webbrowser.open(f'file:///{plugdir.get()}') - ).grid(row=10, column=1, padx=(0, PADX), sticky=tk.NSEW) + ).grid(row=10, column=1, padx=(0, self.PADX), sticky=tk.NSEW) nb.Label( plugsframe, # Help text in settings text=_("Tip: You can disable a plugin by{CR}adding '{EXT}' to its folder name").format(EXT='.disabled') - ).grid(columnspan=2, padx=PADX, pady=10, sticky=tk.NSEW) + ).grid(columnspan=2, padx=self.PADX, pady=10, sticky=tk.NSEW) enabled_plugins = list(filter(lambda x: x.folder and x.module, plug.PLUGINS)) if len(enabled_plugins): - ttk.Separator(plugsframe, orient=tk.HORIZONTAL).grid(columnspan=3, padx=PADX, pady=PADY * 8, sticky=tk.EW) + ttk.Separator(plugsframe, orient=tk.HORIZONTAL).grid(columnspan=3, padx=self.PADX, pady=self.PADY * 8, sticky=tk.EW) nb.Label( plugsframe, text=_('Enabled Plugins')+':' # List of plugins in settings - ).grid(padx=PADX, sticky=tk.W) + ).grid(padx=self.PADX, sticky=tk.W) for plugin in enabled_plugins: if plugin.name == plugin.folder: @@ -651,77 +721,40 @@ class PreferencesDialog(tk.Toplevel): else: label = nb.Label(plugsframe, text=f'{plugin.folder} ({plugin.name})') - label.grid(columnspan=2, padx=PADX*2, sticky=tk.W) + label.grid(columnspan=2, padx=self.PADX*2, sticky=tk.W) ############################################################ # Show which plugins don't have Python 3.x support ############################################################ if len(plug.PLUGINS_not_py3): - ttk.Separator(plugsframe, orient=tk.HORIZONTAL).grid(columnspan=3, padx=PADX, pady=PADY * 8, sticky=tk.EW) - nb.Label(plugsframe, text=_('Plugins Without Python 3.x Support:')+':').grid(padx=PADX, sticky=tk.W) + ttk.Separator(plugsframe, orient=tk.HORIZONTAL).grid(columnspan=3, padx=self.PADX, pady=self.PADY * 8, sticky=tk.EW) + nb.Label(plugsframe, text=_('Plugins Without Python 3.x Support:')+':').grid(padx=self.PADX, sticky=tk.W) for plugin in plug.PLUGINS_not_py3: if plugin.folder: # 'system' ones have this set to None to suppress listing in Plugins prefs tab - nb.Label(plugsframe, text=plugin.name).grid(columnspan=2, padx=PADX*2, sticky=tk.W) + nb.Label(plugsframe, text=plugin.name).grid(columnspan=2, padx=self.PADX*2, sticky=tk.W) HyperlinkLabel( plugsframe, text=_('Information on migrating plugins'), background=nb.Label().cget('background'), url='https://github.com/EDCD/EDMarketConnector/blob/main/PLUGINS.md#migration-to-python-37', underline=True - ).grid(columnspan=2, padx=PADX, sticky=tk.W) + ).grid(columnspan=2, padx=self.PADX, sticky=tk.W) ############################################################ disabled_plugins = list(filter(lambda x: x.folder and not x.module, plug.PLUGINS)) if len(disabled_plugins): - ttk.Separator(plugsframe, orient=tk.HORIZONTAL).grid(columnspan=3, padx=PADX, pady=PADY * 8, sticky=tk.EW) + ttk.Separator(plugsframe, orient=tk.HORIZONTAL).grid(columnspan=3, padx=self.PADX, pady=self.PADY * 8, sticky=tk.EW) nb.Label( plugsframe, text=_('Disabled Plugins')+':' # List of plugins in settings - ).grid(padx=PADX, sticky=tk.W) + ).grid(padx=self.PADX, sticky=tk.W) for plugin in disabled_plugins: - nb.Label(plugsframe, text=plugin.name).grid(columnspan=2, padx=PADX*2, sticky=tk.W) + nb.Label(plugsframe, text=plugin.name).grid(columnspan=2, padx=self.PADX*2, sticky=tk.W) notebook.add(plugsframe, text=_('Plugins')) # Tab heading in settings - if platform == 'darwin': - self.protocol("WM_DELETE_WINDOW", self.apply) # close button applies changes - - else: - buttonframe = ttk.Frame(frame) - buttonframe.grid(padx=PADX, pady=PADX, sticky=tk.NSEW) - buttonframe.columnconfigure(0, weight=1) - ttk.Label(buttonframe).grid(row=0, column=0) # spacer - button = ttk.Button(buttonframe, text=_('OK'), command=self.apply) - button.grid(row=0, column=1, sticky=tk.E) - button.bind("", lambda event: self.apply()) - self.protocol("WM_DELETE_WINDOW", self._destroy) - - # Selectively disable buttons depending on output settings - self.cmdrchanged() - self.themevarchanged() - - # disable hotkey for the duration - hotkeymgr.unregister() - - # wait for window to appear on screen before calling grab_set - self.parent.update_idletasks() - self.parent.wm_attributes('-topmost', 0) # needed for dialog to appear ontop of parent on OSX & Linux - self.wait_visibility() - self.grab_set() - - # Ensure fully on-screen - if platform == 'win32' and CalculatePopupWindowPosition: - position = RECT() - GetWindowRect(GetParent(self.winfo_id()), position) - if CalculatePopupWindowPosition( - POINT(parent.winfo_rootx(), parent.winfo_rooty()), - SIZE(position.right - position.left, position.bottom - position.top), - 0x10000, None, position - ): - self.geometry("+{position.left}+{position.top}") - def cmdrchanged(self, event=None): """ Notify plugins of cmdr change. From 315258d3e72e5b2feae073f4447a8ebde020a191 Mon Sep 17 00:00:00 2001 From: A_D Date: Wed, 16 Sep 2020 19:43:02 +0200 Subject: [PATCH 13/17] Added row tracking variables to config tabs This adds a new class called AutoInc, which is a self-incrementing integer that supports use as a context manager. AutoInc is used to keep track of row numbers automatically for easy addition to config panes, and the context manager adds a visual clue to where entries are on the same row but different columns --- prefs.py | 552 ++++++++++++++++++++++++++++++++----------------------- 1 file changed, 320 insertions(+), 232 deletions(-) diff --git a/prefs.py b/prefs.py index ba675080..63573a40 100644 --- a/prefs.py +++ b/prefs.py @@ -3,12 +3,13 @@ import logging import tkinter as tk +from types import TracebackType import webbrowser from os.path import exists, expanduser, expandvars, join, normpath from sys import platform from tkinter import Variable, colorchooser as tkColorChooser # type: ignore from tkinter import ttk -from typing import TYPE_CHECKING, Any, Callable, Optional, Union +from typing import TYPE_CHECKING, Any, Callable, Optional, Type, Union import myNotebook as nb from myNotebook import Notebook @@ -21,6 +22,8 @@ from monitor import monitor from theme import theme from ttkHyperlinkLabel import HyperlinkLabel +import contextlib + logger = logging.getLogger(appname) if TYPE_CHECKING: @@ -113,8 +116,48 @@ class PrefsVersion: return False ########################################################################### - prefsVersion = PrefsVersion() # noqa: N816 # Cannot rename as used in plugins + + +class AutoInc(contextlib.AbstractContextManager): + """ + Autoinc is a self incrementing int. + + As a context manager, it increments on enter, and does nothing on exit. + """ + + def __init__(self, start: int = 0, step: int = 1) -> None: + self.current = start + self.step = step + + def get(self, increment=True) -> int: + """ + Get the current integer, optionally incrementing it. + + :param increment: whether or not to increment the stored value, defaults to True + :return: the current value + """ + current = self.current + if increment: + self.current += self.step + + return current + + def __enter__(self): + """ + Increments once, alias to .get. + + :return: the current value + """ + return self.get() + + def __exit__( + self, + exc_type: Optional[Type[BaseException]], exc_value: Optional[BaseException], traceback: Optional[TracebackType] + ) -> Optional[bool]: + """Do nothing.""" + return None + ########################################################################### if platform == 'darwin': @@ -144,6 +187,7 @@ if platform == 'darwin': elif platform == 'win32': # sigh tkFileDialog.askdirectory doesn't support unicode on Windows + # TODO: Remove this import ctypes import ctypes.windll # type: ignore # I promise pylance, its there. from ctypes.wintypes import HINSTANCE, HWND, LPARAM, LPCWSTR, LPVOID, LPWSTR, MAX_PATH, POINT, RECT, SIZE, UINT @@ -246,7 +290,7 @@ class PreferencesDialog(tk.Toplevel): self.__setup_output_tab(notebook) self.__setup_plugin_tabs(notebook) self.__setup_config_tab(notebook) - self.__setup_theme_tab(notebook) + self.__setup_appearance_tab(notebook) self.__setup_plugin_tab(notebook) if platform == 'darwin': @@ -287,8 +331,8 @@ class PreferencesDialog(tk.Toplevel): self.geometry(f"+{position.left}+{position.top}") def __setup_output_tab(self, root_notebook: nb.Notebook) -> None: - outframe = nb.Frame(root_notebook) - outframe.columnconfigure(0, weight=1) + output_frame = nb.Frame(root_notebook) + output_frame.columnconfigure(0, weight=1) if prefsVersion.shouldSetDefaults('0.0.0.0', not bool(config.getint('output'))): output = config.OUT_SHIP # default settings @@ -296,157 +340,151 @@ class PreferencesDialog(tk.Toplevel): else: output = config.getint('output') - row = 0 + row = AutoInc(start=1) # TODO: *All* of this needs to use a 'row' variable, incremented after # adding one to keep track, so it's easier to insert new rows in # the middle without worrying about updating `row=X` elements. - self.out_label = nb.Label(outframe, text=_('Please choose what data to save')) - self.out_label.grid(columnspan=2, padx=self.PADX, sticky=tk.W, row=row) - - row += 1 + self.out_label = nb.Label(output_frame, text=_('Please choose what data to save')) + self.out_label.grid(columnspan=2, padx=self.PADX, sticky=tk.W, row=row.get()) self.out_csv = tk.IntVar(value=1 if (output & config.OUT_MKT_CSV) else 0) self.out_csv_button = nb.Checkbutton( - outframe, + output_frame, text=_('Market data in CSV format file'), variable=self.out_csv, command=self.outvarchanged ) - self.out_csv_button.grid(columnspan=2, padx=self.BUTTONX, sticky=tk.W, row=row) - - row += 1 + self.out_csv_button.grid(columnspan=2, padx=self.BUTTONX, sticky=tk.W, row=row.get()) self.out_td = tk.IntVar(value=1 if (output & config.OUT_MKT_TD) else 0) self.out_td_button = nb.Checkbutton( - outframe, + output_frame, text=_('Market data in Trade Dangerous format file'), variable=self.out_td, command=self.outvarchanged ) - self.out_td_button.grid(columnspan=2, padx=self.BUTTONX, sticky=tk.W, row=row) + self.out_td_button.grid(columnspan=2, padx=self.BUTTONX, sticky=tk.W, row=row.get()) self.out_ship = tk.IntVar(value=1 if (output & config.OUT_SHIP) else 0) - row += 1 - # Output setting self.out_ship_button = nb.Checkbutton( - outframe, + output_frame, text=_('Ship loadout'), variable=self.out_ship, command=self.outvarchanged ) - self.out_ship_button.grid(columnspan=2, padx=self.BUTTONX, pady=(5, 0), sticky=tk.W, row=row) + self.out_ship_button.grid(columnspan=2, padx=self.BUTTONX, pady=(5, 0), sticky=tk.W, row=row.get()) self.out_auto = tk.IntVar(value=0 if output & config.OUT_MKT_MANUAL else 1) # inverted - row += 1 - # Output setting self.out_auto_button = nb.Checkbutton( - outframe, + output_frame, text=_('Automatically update on docking'), variable=self.out_auto, command=self.outvarchanged ) - self.out_auto_button.grid(columnspan=2, padx=self.BUTTONX, pady=(5, 0), sticky=tk.W, row=row) - - row += 1 + self.out_auto_button.grid(columnspan=2, padx=self.BUTTONX, pady=(5, 0), sticky=tk.W, row=row.get()) self.outdir = tk.StringVar() self.outdir.set(str(config.get('outdir'))) - self.outdir_label = nb.Label(outframe, text=_('File location')+':') # Section heading in settings - self.outdir_label.grid(padx=self.PADX, pady=(5, 0), sticky=tk.W, row=row) # type: ignore # 2 tuple, each side + self.outdir_label = nb.Label(output_frame, text=_('File location')+':') # Section heading in settings + # Type ignored due to incorrect type annotation. a 2 tuple does padding for each side + self.outdir_label.grid(padx=self.PADX, pady=(5, 0), sticky=tk.W, row=row.get()) # type: ignore - row += 1 - - self.outdir_entry = nb.Entry(outframe, takefocus=False) - self.outdir_entry.grid(columnspan=2, padx=self.PADX, pady=(0, self.PADY), sticky=tk.EW, row=row) + self.outdir_entry = nb.Entry(output_frame, takefocus=False) + self.outdir_entry.grid(columnspan=2, padx=self.PADX, pady=(0, self.PADY), sticky=tk.EW, row=row.get()) - row += 1 - self.outbutton = nb.Button( - outframe, + output_frame, text=(_('Change...') if platform == 'darwin' else _('Browse...')), command=lambda: self.filebrowse(_('File location'), self.outdir) ) - self.outbutton.grid(column=1, padx=self.PADX, pady=self.PADY, sticky=tk.NSEW, row=row) + self.outbutton.grid(column=1, padx=self.PADX, pady=self.PADY, sticky=tk.NSEW, row=row.get()) - row += 1 - - nb.Frame(outframe).grid(row=row) # bottom spacer # TODO: does nothing? + nb.Frame(output_frame).grid(row=row.get()) # bottom spacer # TODO: does nothing? - root_notebook.add(outframe, text=_('Output')) # Tab heading in settings + root_notebook.add(output_frame, text=_('Output')) # Tab heading in settings def __setup_plugin_tabs(self, notebook: Notebook) -> None: for plugin in plug.PLUGINS: - plugframe = plugin.get_prefs(notebook, monitor.cmdr, monitor.is_beta) - if plugframe: - notebook.add(plugframe, text=plugin.name) + plugin_frame = plugin.get_prefs(notebook, monitor.cmdr, monitor.is_beta) + if plugin_frame: + notebook.add(plugin_frame, text=plugin.name) def __setup_config_tab(self, notebook: Notebook) -> None: - configframe = nb.Frame(notebook) - configframe.columnconfigure(1, weight=1) + config_frame = nb.Frame(notebook) + config_frame.columnconfigure(1, weight=1) + row = AutoInc(start=1) self.logdir = tk.StringVar() self.logdir.set(str(config.get('journaldir') or config.default_journal_dir or '')) - self.logdir_entry = nb.Entry(configframe, takefocus=False) + self.logdir_entry = nb.Entry(config_frame, takefocus=False) # Location of the new Journal file in E:D 2.2 nb.Label( - configframe, + config_frame, text=_('E:D journal file location')+':' - ).grid(columnspan=4, padx=self.PADX, sticky=tk.W) + ).grid(columnspan=4, padx=self.PADX, sticky=tk.W, row=row.get()) + + self.logdir_entry.grid(columnspan=4, padx=self.PADX, pady=(0, self.PADY), sticky=tk.EW, row=row.get()) - self.logdir_entry.grid(columnspan=4, padx=self.PADX, pady=(0, self.PADY), sticky=tk.EW) self.logbutton = nb.Button( - configframe, + config_frame, text=(_('Change...') if platform == 'darwin' else _('Browse...')), command=lambda: self.filebrowse(_('E:D journal file location'), self.logdir) ) + self.logbutton.grid(column=3, padx=self.PADX, pady=self.PADY, sticky=tk.EW, row=row.get()) - self.logbutton.grid(row=10, column=3, padx=self.PADX, pady=self.PADY, sticky=tk.EW) if config.default_journal_dir: # Appearance theme and language setting nb.Button( - configframe, + config_frame, text=_('Default'), command=self.logdir_reset, state=tk.NORMAL if config.get('journaldir') else tk.DISABLED - ).grid(row=10, column=2, pady=self.PADY, sticky=tk.EW) + ).grid(column=2, pady=self.PADY, sticky=tk.EW, row=row.get()) + + if platform in ('darwin', 'win32'): + ttk.Separator(config_frame, orient=tk.HORIZONTAL).grid( + columnspan=4, padx=self.PADX, pady=self.PADY*4, sticky=tk.EW, row=row.get() + ) - if platform in ['darwin', 'win32']: - ttk.Separator(configframe, orient=tk.HORIZONTAL).grid(columnspan=4, padx=self.PADX, pady=self.PADY*4, sticky=tk.EW) self.hotkey_code = config.getint('hotkey_code') self.hotkey_mods = config.getint('hotkey_mods') self.hotkey_only = tk.IntVar(value=not config.getint('hotkey_always')) self.hotkey_play = tk.IntVar(value=not config.getint('hotkey_mute')) nb.Label( - configframe, + config_frame, text=_('Keyboard shortcut') if # Hotkey/Shortcut settings prompt on OSX platform == 'darwin' else _('Hotkey') # Hotkey/Shortcut settings prompt on Windows - ).grid(row=20, padx=self.PADX, sticky=tk.W) + ).grid(padx=self.PADX, sticky=tk.W, row=row.get()) if platform == 'darwin' and not was_accessible_at_launch: if AXIsProcessTrusted(): - nb.Label(configframe, text=_('Re-start {APP} to use shortcuts').format(APP=applongname), - foreground='firebrick').grid(padx=self.PADX, sticky=tk.W) # Shortcut settings prompt on OSX + # Shortcut settings prompt on OSX + nb.Label( + config_frame, + text=_('Re-start {APP} to use shortcuts').format(APP=applongname), + foreground='firebrick' + ).grid(padx=self.PADX, sticky=tk.W, row=row.get()) else: # Shortcut settings prompt on OSX nb.Label( - configframe, - text=_('{APP} needs permission to use shortcuts').format( - APP=applongname - ), + config_frame, + text=_('{APP} needs permission to use shortcuts').format(APP=applongname), foreground='firebrick' - ).grid(columnspan=4, padx=self.PADX, sticky=tk.W) + ).grid(columnspan=4, padx=self.PADX, sticky=tk.W, row=row.get()) - nb.Button(configframe, text=_('Open System Preferences'), command=self.enableshortcuts).grid( - padx=self.PADX, sticky=tk.E) # Shortcut settings button on OSX + # Shortcut settings button on OSX + nb.Button(config_frame, text=_('Open System Preferences'), command=self.enableshortcuts).grid( + padx=self.PADX, sticky=tk.E, row=row.get() + ) else: - self.hotkey_text = nb.Entry(configframe, width=(20 if platform == 'darwin' else 30), justify=tk.CENTER) + self.hotkey_text = nb.Entry(config_frame, width=(20 if platform == 'darwin' else 30), justify=tk.CENTER) self.hotkey_text.insert( 0, # No hotkey/shortcut currently defined @@ -456,132 +494,149 @@ class PreferencesDialog(tk.Toplevel): self.hotkey_text.bind('', self.hotkeystart) self.hotkey_text.bind('', self.hotkeyend) - self.hotkey_text.grid(row=20, column=1, columnspan=2, pady=(5, 0), sticky=tk.W) + self.hotkey_text.grid(column=1, columnspan=2, pady=(5, 0), sticky=tk.W, row=row.get()) # Hotkey/Shortcut setting self.hotkey_only_btn = nb.Checkbutton( - configframe, + config_frame, text=_('Only when Elite: Dangerous is the active app'), variable=self.hotkey_only, state=tk.NORMAL if self.hotkey_code else tk.DISABLED ) - self.hotkey_only_btn.grid(columnspan=4, padx=self.PADX, pady=(5, 0), sticky=tk.W) + self.hotkey_only_btn.grid(columnspan=4, padx=self.PADX, pady=(5, 0), sticky=tk.W, row=row.get()) # Hotkey/Shortcut setting self.hotkey_play_btn = nb.Checkbutton( - configframe, + config_frame, text=_('Play sound'), variable=self.hotkey_play, state=tk.NORMAL if self.hotkey_code else tk.DISABLED ) - self.hotkey_play_btn.grid(columnspan=4, padx=self.PADX, sticky=tk.W) + self.hotkey_play_btn.grid(columnspan=4, padx=self.PADX, sticky=tk.W, row=row.get()) # Option to disabled Automatic Check For Updates whilst in-game - ttk.Separator(configframe, orient=tk.HORIZONTAL).grid(columnspan=4, padx=self.PADX, pady=self.PADY*4, sticky=tk.EW) + ttk.Separator(config_frame, orient=tk.HORIZONTAL).grid( + columnspan=4, padx=self.PADX, pady=self.PADY*4, sticky=tk.EW, row=row.get() + ) self.disable_autoappupdatecheckingame = tk.IntVar(value=config.getint('disable_autoappupdatecheckingame')) self.disable_autoappupdatecheckingame_btn = nb.Checkbutton( - configframe, + config_frame, text=_('Disable Automatic Application Updates Check when in-game'), variable=self.disable_autoappupdatecheckingame, command=self.disable_autoappupdatecheckingame_changed ) - self.disable_autoappupdatecheckingame_btn.grid(columnspan=4, padx=self.PADX, sticky=tk.W) + self.disable_autoappupdatecheckingame_btn.grid(columnspan=4, padx=self.PADX, sticky=tk.W, row=row.get()) - ttk.Separator(configframe, orient=tk.HORIZONTAL).grid(columnspan=4, padx=self.PADX, pady=self.PADY*4, sticky=tk.EW) + ttk.Separator(config_frame, orient=tk.HORIZONTAL).grid( + columnspan=4, padx=self.PADX, pady=self.PADY*4, sticky=tk.EW, row=row.get() + ) + # Settings prompt for preferred ship loadout, system and station info websites - nb.Label(configframe, text=_('Preferred websites')).grid(row=30, columnspan=4, padx=self.PADX, sticky=tk.W) - - self.shipyard_provider = tk.StringVar( - value=str( - config.get('shipyard_provider') in plug.provides('shipyard_url') - and config.get('shipyard_provider') or 'EDSY') - ) - # Setting to decide which ship outfitting website to link to - either E:D Shipyard or Coriolis - nb.Label(configframe, text=_('Shipyard')).grid(row=31, padx=self.PADX, pady=2*self.PADY, sticky=tk.W) - self.shipyard_button = nb.OptionMenu( - configframe, self.shipyard_provider, self.shipyard_provider.get(), *plug.provides('shipyard_url') + nb.Label(config_frame, text=_('Preferred websites')).grid( + columnspan=4, padx=self.PADX, sticky=tk.W, row=row.get() ) - self.shipyard_button.configure(width=15) - self.shipyard_button.grid(row=31, column=1, sticky=tk.W) - # Option for alternate URL opening - self.alt_shipyard_open = tk.IntVar(value=config.getint('use_alt_shipyard_open')) - self.alt_shipyard_open_btn = nb.Checkbutton( - configframe, - text=_('Use alternate URL method'), - variable=self.alt_shipyard_open, - command=self.alt_shipyard_open_changed, - ) + with row as cur_row: + self.shipyard_provider = tk.StringVar( + value=str( + config.get('shipyard_provider') in plug.provides('shipyard_url') + and config.get('shipyard_provider') or 'EDSY') + ) + # Setting to decide which ship outfitting website to link to - either E:D Shipyard or Coriolis + nb.Label(config_frame, text=_('Shipyard')).grid(padx=self.PADX, pady=2*self.PADY, sticky=tk.W, row=cur_row) + self.shipyard_button = nb.OptionMenu( + config_frame, self.shipyard_provider, self.shipyard_provider.get(), *plug.provides('shipyard_url') + ) - self.alt_shipyard_open_btn.grid(row=31, column=2, sticky=tk.W) + self.shipyard_button.configure(width=15) + self.shipyard_button.grid(column=1, sticky=tk.W, row=cur_row) + # Option for alternate URL opening + self.alt_shipyard_open = tk.IntVar(value=config.getint('use_alt_shipyard_open')) + self.alt_shipyard_open_btn = nb.Checkbutton( + config_frame, + text=_('Use alternate URL method'), + variable=self.alt_shipyard_open, + command=self.alt_shipyard_open_changed, + ) - system_provider = config.get('system_provider') - self.system_provider = tk.StringVar( - value=str(system_provider if system_provider in plug.provides('system_url') else 'EDSM') - ) + self.alt_shipyard_open_btn.grid(column=2, sticky=tk.W, row=cur_row) - nb.Label(configframe, text=_('System')).grid(row=32, padx=self.PADX, pady=2*self.PADY, sticky=tk.W) - self.system_button = nb.OptionMenu( - configframe, - self.system_provider, - self.system_provider.get(), - *plug.provides('system_url') - ) + with row as cur_row: + system_provider = config.get('system_provider') + self.system_provider = tk.StringVar( + value=str(system_provider if system_provider in plug.provides('system_url') else 'EDSM') + ) - self.system_button.configure(width=15) - self.system_button.grid(row=32, column=1, sticky=tk.W) + nb.Label(config_frame, text=_('System')).grid(padx=self.PADX, pady=2*self.PADY, sticky=tk.W, row=cur_row) + self.system_button = nb.OptionMenu( + config_frame, + self.system_provider, + self.system_provider.get(), + *plug.provides('system_url') + ) - station_provider = config.get('station_provider') - self.station_provider = tk.StringVar( - value=str(station_provider if station_provider in plug.provides('station_url') else 'eddb') - ) + self.system_button.configure(width=15) + self.system_button.grid(column=1, sticky=tk.W, row=cur_row) - nb.Label(configframe, text=_('Station')).grid(row=33, padx=self.PADX, pady=2*self.PADY, sticky=tk.W) - self.station_button = nb.OptionMenu( - configframe, - self.station_provider, - self.station_provider.get(), - *plug.provides('station_url') - ) + with row as cur_row: + station_provider = config.get('station_provider') + self.station_provider = tk.StringVar( + value=str(station_provider if station_provider in plug.provides('station_url') else 'eddb') + ) - self.station_button.configure(width=15) - self.station_button.grid(row=33, column=1, sticky=tk.W) + nb.Label(config_frame, text=_('Station')).grid(padx=self.PADX, pady=2*self.PADY, sticky=tk.W, row=cur_row) + self.station_button = nb.OptionMenu( + config_frame, + self.station_provider, + self.station_provider.get(), + *plug.provides('station_url') + ) + + self.station_button.configure(width=15) + self.station_button.grid(column=1, sticky=tk.W, row=cur_row) # Set loglevel - ttk.Separator(configframe, orient=tk.HORIZONTAL).grid(columnspan=4, padx=self.PADX, pady=self.PADY*4, sticky=tk.EW) - - # Set the current loglevel - nb.Label( - configframe, - text=_('Log Level') - ).grid(row=35, padx=self.PADX, pady=2*self.PADY, sticky=tk.W) - - current_loglevel = config.get('loglevel') - if not current_loglevel: - current_loglevel = logging.getLevelName(logging.INFO) - self.select_loglevel = tk.StringVar(value=str(current_loglevel)) - loglevels = list( - map(logging.getLevelName, (logging.CRITICAL, logging.ERROR, logging.WARNING, logging.INFO, logging.DEBUG)) + ttk.Separator(config_frame, orient=tk.HORIZONTAL).grid( + columnspan=4, padx=self.PADX, pady=self.PADY*4, sticky=tk.EW, row=row.get() ) - self.loglevel_dropdown = nb.OptionMenu( - configframe, - self.select_loglevel, - self.select_loglevel.get(), - *loglevels - ) + with row as cur_row: + # Set the current loglevel + nb.Label( + config_frame, + text=_('Log Level') + ).grid(padx=self.PADX, pady=2*self.PADY, sticky=tk.W, row=cur_row) - self.loglevel_dropdown.configure(width=15) - self.loglevel_dropdown.grid(row=35, column=1, sticky=tk.W) + current_loglevel = config.get('loglevel') + if not current_loglevel: + current_loglevel = logging.getLevelName(logging.INFO) + + self.select_loglevel = tk.StringVar(value=str(current_loglevel)) + loglevels = list( + map(logging.getLevelName, ( + logging.CRITICAL, logging.ERROR, logging.WARNING, logging.INFO, logging.DEBUG + )) + ) + + self.loglevel_dropdown = nb.OptionMenu( + config_frame, + self.select_loglevel, + self.select_loglevel.get(), + *loglevels + ) + + self.loglevel_dropdown.configure(width=15) + self.loglevel_dropdown.grid(column=1, sticky=tk.W, row=cur_row) # Big spacer - nb.Label(configframe).grid(sticky=tk.W) + nb.Label(config_frame).grid(sticky=tk.W, row=row.get()) - notebook.add(configframe, text=_('Configuration')) # Tab heading in settings + notebook.add(config_frame, text=_('Configuration')) # Tab heading in settings + def __setup_appearance_tab(self, notebook: Notebook) -> None: self.languages = Translations.available_names() # Appearance theme and language setting self.lang = tk.StringVar(value=self.languages.get(config.get('language'), _('Default'))) @@ -593,50 +648,65 @@ class PreferencesDialog(tk.Toplevel): _('Highlighted text'), # Dark theme color setting ] - def __setup_theme_tab(self, notebook: Notebook) -> None: - themeframe = nb.Frame(notebook) - themeframe.columnconfigure(2, weight=1) - nb.Label(themeframe, text=_('Language')).grid(row=10, padx=self.PADX, sticky=tk.W) # Appearance setting prompt - self.lang_button = nb.OptionMenu(themeframe, self.lang, self.lang.get(), *self.languages.values()) - self.lang_button.grid(row=10, column=1, columnspan=2, padx=self.PADX, sticky=tk.W) - ttk.Separator(themeframe, orient=tk.HORIZONTAL).grid(columnspan=3, padx=self.PADX, pady=self.PADY*4, sticky=tk.EW) - nb.Label(themeframe, text=_('Theme')).grid(columnspan=3, padx=self.PADX, sticky=tk.W) # Appearance setting - nb.Radiobutton(themeframe, text=_('Default'), variable=self.theme, value=0, command=self.themevarchanged).grid( - columnspan=3, padx=self.BUTTONX, sticky=tk.W) # Appearance theme and language setting - nb.Radiobutton(themeframe, text=_('Dark'), variable=self.theme, value=1, command=self.themevarchanged).grid( - columnspan=3, padx=self.BUTTONX, sticky=tk.W) # Appearance theme setting + row = AutoInc(start=1) + + appearance_frame = nb.Frame(notebook) + appearance_frame.columnconfigure(2, weight=1) + with row as cur_row: + nb.Label(appearance_frame, text=_('Language')).grid(padx=self.PADX, sticky=tk.W, row=cur_row) + self.lang_button = nb.OptionMenu(appearance_frame, self.lang, self.lang.get(), *self.languages.values()) + self.lang_button.grid(column=1, columnspan=2, padx=self.PADX, sticky=tk.W, row=cur_row) + + ttk.Separator(appearance_frame, orient=tk.HORIZONTAL).grid( + columnspan=3, padx=self.PADX, pady=self.PADY*4, sticky=tk.EW, row=row.get() + ) + + # Appearance setting + nb.Label(appearance_frame, text=_('Theme')).grid(columnspan=3, padx=self.PADX, sticky=tk.W, row=row.get()) + + # Appearance theme and language setting + nb.Radiobutton(appearance_frame, text=_('Default'), variable=self.theme, value=0, command=self.themevarchanged).grid( + columnspan=3, padx=self.BUTTONX, sticky=tk.W, row=row.get() + ) + + # Appearance theme setting + nb.Radiobutton(appearance_frame, text=_('Dark'), variable=self.theme, value=1, command=self.themevarchanged).grid( + columnspan=3, padx=self.BUTTONX, sticky=tk.W, row=row.get()) if platform == 'win32': nb.Radiobutton( - themeframe, + appearance_frame, text=_('Transparent'), # Appearance theme setting variable=self.theme, value=2, command=self.themevarchanged - ).grid(columnspan=3, padx=self.BUTTONX, sticky=tk.W) + ).grid(columnspan=3, padx=self.BUTTONX, sticky=tk.W, row=row.get()) - self.theme_label_0 = nb.Label(themeframe, text=self.theme_prompts[0]) - self.theme_label_0.grid(row=20, padx=self.PADX, sticky=tk.W) + with row as cur_row: + self.theme_label_0 = nb.Label(appearance_frame, text=self.theme_prompts[0]) + self.theme_label_0.grid(padx=self.PADX, sticky=tk.W, row=cur_row) - # Main window - self.theme_button_0 = nb.ColoredButton( - themeframe, - text=_('Station'), - background='grey4', - command=lambda: self.themecolorbrowse(0) - ) + # Main window + self.theme_button_0 = nb.ColoredButton( + appearance_frame, + text=_('Station'), + background='grey4', + command=lambda: self.themecolorbrowse(0) + ) - self.theme_button_0.grid(row=20, column=1, padx=self.PADX, pady=self.PADY, sticky=tk.NSEW) - self.theme_label_1 = nb.Label(themeframe, text=self.theme_prompts[1]) - self.theme_label_1.grid(row=21, padx=self.PADX, sticky=tk.W) - self.theme_button_1 = nb.ColoredButton( - themeframe, - text=' Hutton Orbital ', # Do not translate - background='grey4', - command=lambda: self.themecolorbrowse(1) - ) + self.theme_button_0.grid(column=1, padx=self.PADX, pady=self.PADY, sticky=tk.NSEW, row=cur_row) + + with row as cur_row: + self.theme_label_1 = nb.Label(appearance_frame, text=self.theme_prompts[1]) + self.theme_label_1.grid(padx=self.PADX, sticky=tk.W, row=cur_row) + self.theme_button_1 = nb.ColoredButton( + appearance_frame, + text=' Hutton Orbital ', # Do not translate + background='grey4', + command=lambda: self.themecolorbrowse(1) + ) - self.theme_button_1.grid(row=21, column=1, padx=self.PADX, pady=self.PADY, sticky=tk.NSEW) + self.theme_button_1.grid(column=1, padx=self.PADX, pady=self.PADY, sticky=tk.NSEW, row=cur_row) # UI Scaling """ @@ -646,96 +716,110 @@ class PreferencesDialog(tk.Toplevel): So, if at startup we find tk-scaling is 1.33 and have a user setting of 200 we'll end up setting 2.66 as the tk-scaling value. """ - ttk.Separator(themeframe, orient=tk.HORIZONTAL).grid(columnspan=4, padx=self.PADX, pady=self.PADY*4, sticky=tk.EW) - nb.Label(themeframe, text=_('UI Scale Percentage')).grid(row=23, padx=self.PADX, pady=2*self.PADY, sticky=tk.W) - self.ui_scale = tk.IntVar() - self.ui_scale.set(config.getint('ui_scale')) - self.uiscale_bar = tk.Scale( - themeframe, - variable=self.ui_scale, # TODO: intvar, but annotated as DoubleVar - orient=tk.HORIZONTAL, - length=300 * (float(theme.startup_ui_scale) / 100.0 * theme.default_ui_scale), - from_=0, - to=400, - tickinterval=50, - resolution=10, + ttk.Separator(appearance_frame, orient=tk.HORIZONTAL).grid( + columnspan=4, padx=self.PADX, pady=self.PADY*4, sticky=tk.EW, row=row.get() ) + with row as cur_row: + nb.Label(appearance_frame, text=_('UI Scale Percentage')).grid( + padx=self.PADX, pady=2*self.PADY, sticky=tk.W, row=cur_row + ) - self.uiscale_bar.grid(row=23, column=1, sticky=tk.W) - self.ui_scaling_defaultis = nb.Label( - themeframe, - text=_('100 means Default{CR}Restart Required for{CR}changes to take effect!') - ).grid(row=23, column=3, padx=PADX, pady=2*PADY, sticky=tk.E) + self.ui_scale = tk.IntVar() + self.ui_scale.set(config.getint('ui_scale')) + self.uiscale_bar = tk.Scale( + appearance_frame, + variable=self.ui_scale, # TODO: intvar, but annotated as DoubleVar + orient=tk.HORIZONTAL, + length=300 * (float(theme.startup_ui_scale) / 100.0 * theme.default_ui_scale), # type: ignore # runtime + from_=0, + to=400, + tickinterval=50, + resolution=10, + ) + + self.uiscale_bar.grid(column=1, sticky=tk.W, row=cur_row) + self.ui_scaling_defaultis = nb.Label( + appearance_frame, + text=_('100 means Default{CR}Restart Required for{CR}changes to take effect!') + ).grid(column=3, padx=self.PADX, pady=2*self.PADY, sticky=tk.E, row=cur_row) # Always on top - ttk.Separator(themeframe, orient=tk.HORIZONTAL).grid(columnspan=3, padx=self.PADX, pady=self.PADY*4, sticky=tk.EW) + ttk.Separator(appearance_frame, orient=tk.HORIZONTAL).grid( + columnspan=3, padx=self.PADX, pady=self.PADY*4, sticky=tk.EW, row=row.get() + ) + self.ontop_button = nb.Checkbutton( - themeframe, + appearance_frame, text=_('Always on top'), variable=self.always_ontop, command=self.themevarchanged ) + self.ontop_button.grid(columnspan=3, padx=self.BUTTONX, sticky=tk.W, row=cur_row) # Appearance setting + + nb.Label(appearance_frame).grid(sticky=tk.W) # big spacer - self.ontop_button.grid(columnspan=3, padx=self.BUTTONX, sticky=tk.W) # Appearance setting - nb.Label(themeframe).grid(sticky=tk.W) # big spacer - - notebook.add(themeframe, text=_('Appearance')) # Tab heading in settings + notebook.add(appearance_frame, text=_('Appearance')) # Tab heading in settings def __setup_plugin_tab(self, notebook: Notebook) -> None: # Plugin tab itself # Plugin settings and info - plugsframe = nb.Frame(notebook) - plugsframe.columnconfigure(0, weight=1) + plugins_frame = nb.Frame(notebook) + plugins_frame.columnconfigure(0, weight=1) plugdir = tk.StringVar() plugdir.set(config.plugin_dir) + row = AutoInc(1) - nb.Label(plugsframe, text=_('Plugins folder')+':').grid(padx=self.PADX, sticky=tk.W) # Section heading in settings - plugdirentry = nb.Entry(plugsframe, justify=tk.LEFT) + # Section heading in settings + nb.Label(plugins_frame, text=_('Plugins folder')+':').grid(padx=self.PADX, sticky=tk.W) + plugdirentry = nb.Entry(plugins_frame, justify=tk.LEFT) self.displaypath(plugdir, plugdirentry) - plugdirentry.grid(row=10, padx=self.PADX, sticky=tk.EW) + with row as cur_row: + plugdirentry.grid(padx=self.PADX, sticky=tk.EW, row=cur_row) - nb.Button( - plugsframe, - text=_('Open'), # Button that opens a folder in Explorer/Finder - command=lambda: webbrowser.open(f'file:///{plugdir.get()}') - ).grid(row=10, column=1, padx=(0, self.PADX), sticky=tk.NSEW) + nb.Button( + plugins_frame, + text=_('Open'), # Button that opens a folder in Explorer/Finder + command=lambda: webbrowser.open(f'file:///{plugdir.get()}') + ).grid(column=1, padx=(0, self.PADX), sticky=tk.NSEW, row=cur_row) nb.Label( - plugsframe, + plugins_frame, # Help text in settings text=_("Tip: You can disable a plugin by{CR}adding '{EXT}' to its folder name").format(EXT='.disabled') - ).grid(columnspan=2, padx=self.PADX, pady=10, sticky=tk.NSEW) + ).grid(columnspan=2, padx=self.PADX, pady=10, sticky=tk.NSEW, row=row.get()) enabled_plugins = list(filter(lambda x: x.folder and x.module, plug.PLUGINS)) if len(enabled_plugins): - ttk.Separator(plugsframe, orient=tk.HORIZONTAL).grid(columnspan=3, padx=self.PADX, pady=self.PADY * 8, sticky=tk.EW) + ttk.Separator(plugins_frame, orient=tk.HORIZONTAL).grid(columnspan=3, padx=self.PADX, pady=self.PADY * 8, sticky=tk.EW) nb.Label( - plugsframe, + plugins_frame, text=_('Enabled Plugins')+':' # List of plugins in settings - ).grid(padx=self.PADX, sticky=tk.W) + ).grid(padx=self.PADX, sticky=tk.W, row=row.get()) for plugin in enabled_plugins: if plugin.name == plugin.folder: - label = nb.Label(plugsframe, text=plugin.name) + label = nb.Label(plugins_frame, text=plugin.name) else: - label = nb.Label(plugsframe, text=f'{plugin.folder} ({plugin.name})') + label = nb.Label(plugins_frame, text=f'{plugin.folder} ({plugin.name})') - label.grid(columnspan=2, padx=self.PADX*2, sticky=tk.W) + label.grid(columnspan=2, padx=self.PADX*2, sticky=tk.W, row=row.get()) ############################################################ # Show which plugins don't have Python 3.x support ############################################################ if len(plug.PLUGINS_not_py3): - ttk.Separator(plugsframe, orient=tk.HORIZONTAL).grid(columnspan=3, padx=self.PADX, pady=self.PADY * 8, sticky=tk.EW) - nb.Label(plugsframe, text=_('Plugins Without Python 3.x Support:')+':').grid(padx=self.PADX, sticky=tk.W) + ttk.Separator(plugins_frame, orient=tk.HORIZONTAL).grid( + columnspan=3, padx=self.PADX, pady=self.PADY * 8, sticky=tk.EW, row=row.get() + ) + nb.Label(plugins_frame, text=_('Plugins Without Python 3.x Support:')+':').grid(padx=self.PADX, sticky=tk.W) for plugin in plug.PLUGINS_not_py3: if plugin.folder: # 'system' ones have this set to None to suppress listing in Plugins prefs tab - nb.Label(plugsframe, text=plugin.name).grid(columnspan=2, padx=self.PADX*2, sticky=tk.W) + nb.Label(plugins_frame, text=plugin.name).grid(columnspan=2, padx=self.PADX*2, sticky=tk.W) HyperlinkLabel( - plugsframe, text=_('Information on migrating plugins'), + plugins_frame, text=_('Information on migrating plugins'), background=nb.Label().cget('background'), url='https://github.com/EDCD/EDMarketConnector/blob/main/PLUGINS.md#migration-to-python-37', underline=True @@ -744,16 +828,20 @@ class PreferencesDialog(tk.Toplevel): disabled_plugins = list(filter(lambda x: x.folder and not x.module, plug.PLUGINS)) if len(disabled_plugins): - ttk.Separator(plugsframe, orient=tk.HORIZONTAL).grid(columnspan=3, padx=self.PADX, pady=self.PADY * 8, sticky=tk.EW) + ttk.Separator(plugins_frame, orient=tk.HORIZONTAL).grid( + columnspan=3, padx=self.PADX, pady=self.PADY * 8, sticky=tk.EW, row=row.get() + ) nb.Label( - plugsframe, + plugins_frame, text=_('Disabled Plugins')+':' # List of plugins in settings - ).grid(padx=self.PADX, sticky=tk.W) + ).grid(padx=self.PADX, sticky=tk.W, row=row.get()) for plugin in disabled_plugins: - nb.Label(plugsframe, text=plugin.name).grid(columnspan=2, padx=self.PADX*2, sticky=tk.W) + nb.Label(plugins_frame, text=plugin.name).grid( + columnspan=2, padx=self.PADX*2, sticky=tk.W, row=row.get() + ) - notebook.add(plugsframe, text=_('Plugins')) # Tab heading in settings + notebook.add(plugins_frame, text=_('Plugins')) # Tab heading in settings def cmdrchanged(self, event=None): """ From 0fec834fb9c0f6ea2d1e821eadae48176d6d97d1 Mon Sep 17 00:00:00 2001 From: A_D Date: Wed, 16 Sep 2020 20:27:03 +0200 Subject: [PATCH 14/17] fixed always on top location --- prefs.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/prefs.py b/prefs.py index 63573a40..4b24b190 100644 --- a/prefs.py +++ b/prefs.py @@ -754,7 +754,7 @@ class PreferencesDialog(tk.Toplevel): variable=self.always_ontop, command=self.themevarchanged ) - self.ontop_button.grid(columnspan=3, padx=self.BUTTONX, sticky=tk.W, row=cur_row) # Appearance setting + self.ontop_button.grid(columnspan=3, padx=self.BUTTONX, sticky=tk.W, row=row.get()) # Appearance setting nb.Label(appearance_frame).grid(sticky=tk.W) # big spacer From 74372b997d4e683318e3a29e6684eca45e3896c2 Mon Sep 17 00:00:00 2001 From: A_D Date: Wed, 16 Sep 2020 20:30:28 +0200 Subject: [PATCH 15/17] removed invalid magic import --- prefs.py | 1 - 1 file changed, 1 deletion(-) diff --git a/prefs.py b/prefs.py index 4b24b190..478eb9ef 100644 --- a/prefs.py +++ b/prefs.py @@ -189,7 +189,6 @@ elif platform == 'win32': # sigh tkFileDialog.askdirectory doesn't support unicode on Windows # TODO: Remove this import ctypes - import ctypes.windll # type: ignore # I promise pylance, its there. from ctypes.wintypes import HINSTANCE, HWND, LPARAM, LPCWSTR, LPVOID, LPWSTR, MAX_PATH, POINT, RECT, SIZE, UINT SHGetLocalizedName = ctypes.windll.shell32.SHGetLocalizedName From 175d17192498573cfad8758822571030e5ad81ea Mon Sep 17 00:00:00 2001 From: A_D Date: Wed, 16 Sep 2020 22:09:10 +0200 Subject: [PATCH 16/17] replaced wine check, final cleanups --- prefs.py | 98 ++++++++++++++++++++++++-------------------------------- 1 file changed, 41 insertions(+), 57 deletions(-) diff --git a/prefs.py b/prefs.py index 478eb9ef..16ae1616 100644 --- a/prefs.py +++ b/prefs.py @@ -1,29 +1,28 @@ # -*- coding: utf-8 -*- """EDMC preferences library.""" +import contextlib import logging import tkinter as tk -from types import TracebackType import webbrowser from os.path import exists, expanduser, expandvars, join, normpath from sys import platform -from tkinter import Variable, colorchooser as tkColorChooser # type: ignore +from tkinter import colorchooser as tkColorChooser # type: ignore # noqa: N812 from tkinter import ttk +from types import TracebackType from typing import TYPE_CHECKING, Any, Callable, Optional, Type, Union -import myNotebook as nb -from myNotebook import Notebook +import myNotebook as nb # noqa: N813 import plug from config import applongname, appname, appversion, config from EDMCLogging import edmclogger from hotkey import hotkeymgr from l10n import Translations from monitor import monitor +from myNotebook import Notebook from theme import theme from ttkHyperlinkLabel import HyperlinkLabel -import contextlib - logger = logging.getLogger(appname) if TYPE_CHECKING: @@ -116,6 +115,7 @@ class PrefsVersion: return False ########################################################################### + prefsVersion = PrefsVersion() # noqa: N816 # Cannot rename as used in plugins @@ -154,12 +154,13 @@ class AutoInc(contextlib.AbstractContextManager): def __exit__( self, exc_type: Optional[Type[BaseException]], exc_value: Optional[BaseException], traceback: Optional[TracebackType] - ) -> Optional[bool]: + ) -> Optional[bool]: """Do nothing.""" return None ########################################################################### + if platform == 'darwin': import objc # type: ignore from Foundation import NSFileManager # type: ignore @@ -186,44 +187,21 @@ if platform == 'darwin': was_accessible_at_launch = AXIsProcessTrusted() # type: ignore elif platform == 'win32': - # sigh tkFileDialog.askdirectory doesn't support unicode on Windows - # TODO: Remove this import ctypes - from ctypes.wintypes import HINSTANCE, HWND, LPARAM, LPCWSTR, LPVOID, LPWSTR, MAX_PATH, POINT, RECT, SIZE, UINT - - SHGetLocalizedName = ctypes.windll.shell32.SHGetLocalizedName - SHGetLocalizedName.argtypes = [LPCWSTR, LPWSTR, UINT, ctypes.POINTER(ctypes.c_int)] - - LoadString = ctypes.windll.user32.LoadStringW - LoadString.argtypes = [HINSTANCE, UINT, LPWSTR, ctypes.c_int] - - # https://msdn.microsoft.com/en-us/library/windows/desktop/bb762115 - BIF_RETURNONLYFSDIRS = 0x00000001 - BIF_USENEWUI = 0x00000050 - BFFM_INITIALIZED = 1 - BFFM_SETSELECTION = 0x00000467 - BrowseCallbackProc = ctypes.WINFUNCTYPE(ctypes.c_int, HWND, ctypes.c_uint, LPARAM, LPARAM) - - class BROWSEINFO(ctypes.Structure): - """ - BROWSEINFO class for use in calls to win32 file browser invocation. - - See https://docs.microsoft.com/en-us/windows/win32/api/shlobj_core/ns-shlobj_core-browseinfoa for more - information regarding this structure - """ - - _fields_ = [ - ("hwndOwner", HWND), - ("pidlRoot", LPVOID), - ("pszDisplayName", LPWSTR), - ("lpszTitle", LPCWSTR), - ("ulFlags", UINT), - ("lpfn", BrowseCallbackProc), - ("lParam", LPCWSTR), - ("iImage", ctypes.c_int) - ] - + import winreg + from ctypes.wintypes import HINSTANCE, HWND, LPCWSTR, LPWSTR, MAX_PATH, POINT, RECT, SIZE, UINT + is_wine = False try: + WINE_REGISTRY_KEY = r'HKEY_LOCAL_MACHINE\Software\Wine' + reg = winreg.ConnectRegistry(None, winreg.HKEY_LOCAL_MACHINE) + winreg.OpenKey(reg, WINE_REGISTRY_KEY) + is_wine = True + + except OSError: + pass + + CalculatePopupWindowPosition = None + if not is_wine: CalculatePopupWindowPosition = ctypes.windll.user32.CalculatePopupWindowPosition CalculatePopupWindowPosition.argtypes = [ ctypes.POINTER(POINT), @@ -238,8 +216,11 @@ elif platform == 'win32': GetWindowRect = ctypes.windll.user32.GetWindowRect GetWindowRect.argtypes = [HWND, ctypes.POINTER(RECT)] - except Exception: # Not supported under Wine 4.0 - CalculatePopupWindowPosition = None + SHGetLocalizedName = ctypes.windll.shell32.SHGetLocalizedName + SHGetLocalizedName.argtypes = [LPCWSTR, LPWSTR, UINT, ctypes.POINTER(ctypes.c_int)] + + LoadString = ctypes.windll.user32.LoadStringW + LoadString.argtypes = [HINSTANCE, UINT, LPWSTR, ctypes.c_int] class PreferencesDialog(tk.Toplevel): @@ -390,7 +371,7 @@ class PreferencesDialog(tk.Toplevel): self.outdir_label = nb.Label(output_frame, text=_('File location')+':') # Section heading in settings # Type ignored due to incorrect type annotation. a 2 tuple does padding for each side self.outdir_label.grid(padx=self.PADX, pady=(5, 0), sticky=tk.W, row=row.get()) # type: ignore - + self.outdir_entry = nb.Entry(output_frame, takefocus=False) self.outdir_entry.grid(columnspan=2, padx=self.PADX, pady=(0, self.PADY), sticky=tk.EW, row=row.get()) @@ -400,7 +381,7 @@ class PreferencesDialog(tk.Toplevel): command=lambda: self.filebrowse(_('File location'), self.outdir) ) self.outbutton.grid(column=1, padx=self.PADX, pady=self.PADY, sticky=tk.NSEW, row=row.get()) - + nb.Frame(output_frame).grid(row=row.get()) # bottom spacer # TODO: does nothing? root_notebook.add(output_frame, text=_('Output')) # Tab heading in settings @@ -532,7 +513,7 @@ class PreferencesDialog(tk.Toplevel): ttk.Separator(config_frame, orient=tk.HORIZONTAL).grid( columnspan=4, padx=self.PADX, pady=self.PADY*4, sticky=tk.EW, row=row.get() ) - + # Settings prompt for preferred ship loadout, system and station info websites nb.Label(config_frame, text=_('Preferred websites')).grid( columnspan=4, padx=self.PADX, sticky=tk.W, row=row.get() @@ -662,15 +643,16 @@ class PreferencesDialog(tk.Toplevel): # Appearance setting nb.Label(appearance_frame, text=_('Theme')).grid(columnspan=3, padx=self.PADX, sticky=tk.W, row=row.get()) - + # Appearance theme and language setting - nb.Radiobutton(appearance_frame, text=_('Default'), variable=self.theme, value=0, command=self.themevarchanged).grid( - columnspan=3, padx=self.BUTTONX, sticky=tk.W, row=row.get() - ) + nb.Radiobutton( + appearance_frame, text=_('Default'), variable=self.theme, value=0, command=self.themevarchanged + ).grid(columnspan=3, padx=self.BUTTONX, sticky=tk.W, row=row.get()) # Appearance theme setting - nb.Radiobutton(appearance_frame, text=_('Dark'), variable=self.theme, value=1, command=self.themevarchanged).grid( - columnspan=3, padx=self.BUTTONX, sticky=tk.W, row=row.get()) + nb.Radiobutton( + appearance_frame, text=_('Dark'), variable=self.theme, value=1, command=self.themevarchanged + ).grid(columnspan=3, padx=self.BUTTONX, sticky=tk.W, row=row.get()) if platform == 'win32': nb.Radiobutton( @@ -694,7 +676,7 @@ class PreferencesDialog(tk.Toplevel): ) self.theme_button_0.grid(column=1, padx=self.PADX, pady=self.PADY, sticky=tk.NSEW, row=cur_row) - + with row as cur_row: self.theme_label_1 = nb.Label(appearance_frame, text=self.theme_prompts[1]) self.theme_label_1.grid(padx=self.PADX, sticky=tk.W, row=cur_row) @@ -754,7 +736,7 @@ class PreferencesDialog(tk.Toplevel): command=self.themevarchanged ) self.ontop_button.grid(columnspan=3, padx=self.BUTTONX, sticky=tk.W, row=row.get()) # Appearance setting - + nb.Label(appearance_frame).grid(sticky=tk.W) # big spacer notebook.add(appearance_frame, text=_('Appearance')) # Tab heading in settings @@ -789,7 +771,9 @@ class PreferencesDialog(tk.Toplevel): enabled_plugins = list(filter(lambda x: x.folder and x.module, plug.PLUGINS)) if len(enabled_plugins): - ttk.Separator(plugins_frame, orient=tk.HORIZONTAL).grid(columnspan=3, padx=self.PADX, pady=self.PADY * 8, sticky=tk.EW) + ttk.Separator(plugins_frame, orient=tk.HORIZONTAL).grid( + columnspan=3, padx=self.PADX, pady=self.PADY * 8, sticky=tk.EW + ) nb.Label( plugins_frame, text=_('Enabled Plugins')+':' # List of plugins in settings From 9231fe96fc3944c53e1a028911aa2d0200fa69f2 Mon Sep 17 00:00:00 2001 From: A_D Date: Wed, 16 Sep 2020 22:26:32 +0200 Subject: [PATCH 17/17] removed unused configs --- prefs.py | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/prefs.py b/prefs.py index 16ae1616..ebcff0f4 100644 --- a/prefs.py +++ b/prefs.py @@ -74,11 +74,6 @@ class PrefsVersion: return self.versions['current'] - ########################################################################### - # Should defaults be set, given the settings were added after 'addedAfter' ? - # - # config.get('PrefsVersion') is the version preferences we last saved for - ########################################################################### def shouldSetDefaults(self, addedAfter: str, oldTest: bool = True) -> bool: # noqa: N802,N803 # used in plugins """ Whether or not defaults should be set if they were added after the specified version. @@ -88,6 +83,8 @@ class PrefsVersion: :raises ValueError: on serial number after the current latest :return: bool indicating the answer """ + + # config.get('PrefsVersion') is the version preferences we last saved for pv = config.getint('PrefsVersion') # If no PrefsVersion yet exists then return oldTest if not pv: @@ -113,7 +110,6 @@ class PrefsVersion: return True return False - ########################################################################### prefsVersion = PrefsVersion() # noqa: N816 # Cannot rename as used in plugins @@ -158,8 +154,6 @@ class AutoInc(contextlib.AbstractContextManager): """Do nothing.""" return None -########################################################################### - if platform == 'darwin': import objc # type: ignore @@ -266,7 +260,6 @@ class PreferencesDialog(tk.Toplevel): self.PADY = 2 # close spacing # Set up different tabs - # TODO: modify these to be "__create_$tab_tab" and have them return the frame rather than set it up themselves self.__setup_output_tab(notebook) self.__setup_plugin_tabs(notebook) self.__setup_config_tab(notebook) @@ -322,9 +315,6 @@ class PreferencesDialog(tk.Toplevel): row = AutoInc(start=1) - # TODO: *All* of this needs to use a 'row' variable, incremented after - # adding one to keep track, so it's easier to insert new rows in - # the middle without worrying about updating `row=X` elements. self.out_label = nb.Label(output_frame, text=_('Please choose what data to save')) self.out_label.grid(columnspan=2, padx=self.PADX, sticky=tk.W, row=row.get()) @@ -742,7 +732,6 @@ class PreferencesDialog(tk.Toplevel): notebook.add(appearance_frame, text=_('Appearance')) # Tab heading in settings def __setup_plugin_tab(self, notebook: Notebook) -> None: - # Plugin tab itself # Plugin settings and info plugins_frame = nb.Frame(notebook) plugins_frame.columnconfigure(0, weight=1) @@ -1061,7 +1050,7 @@ class PreferencesDialog(tk.Toplevel): else: config.set('journaldir', logdir) - if platform in ['darwin', 'win32']: + if platform in ('darwin', 'win32'): config.set('hotkey_code', self.hotkey_code) config.set('hotkey_mods', self.hotkey_mods) config.set('hotkey_always', int(not self.hotkey_only.get()))