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

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
This commit is contained in:
A_D 2020-09-16 19:43:02 +02:00
parent 871838106f
commit 315258d3e7
No known key found for this signature in database
GPG Key ID: 4BE9EB7DF45076C4

550
prefs.py
View File

@ -3,12 +3,13 @@
import logging import logging
import tkinter as tk import tkinter as tk
from types import TracebackType
import webbrowser import webbrowser
from os.path import exists, expanduser, expandvars, join, normpath from os.path import exists, expanduser, expandvars, join, normpath
from sys import platform from sys import platform
from tkinter import Variable, colorchooser as tkColorChooser # type: ignore from tkinter import Variable, colorchooser as tkColorChooser # type: ignore
from tkinter import ttk 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 import myNotebook as nb
from myNotebook import Notebook from myNotebook import Notebook
@ -21,6 +22,8 @@ from monitor import monitor
from theme import theme from theme import theme
from ttkHyperlinkLabel import HyperlinkLabel from ttkHyperlinkLabel import HyperlinkLabel
import contextlib
logger = logging.getLogger(appname) logger = logging.getLogger(appname)
if TYPE_CHECKING: if TYPE_CHECKING:
@ -113,8 +116,48 @@ class PrefsVersion:
return False return False
########################################################################### ###########################################################################
prefsVersion = PrefsVersion() # noqa: N816 # Cannot rename as used in plugins 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': if platform == 'darwin':
@ -144,6 +187,7 @@ if platform == 'darwin':
elif platform == 'win32': elif platform == 'win32':
# sigh tkFileDialog.askdirectory doesn't support unicode on Windows # sigh tkFileDialog.askdirectory doesn't support unicode on Windows
# TODO: Remove this
import ctypes import ctypes
import ctypes.windll # type: ignore # I promise pylance, its there. 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 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_output_tab(notebook)
self.__setup_plugin_tabs(notebook) self.__setup_plugin_tabs(notebook)
self.__setup_config_tab(notebook) self.__setup_config_tab(notebook)
self.__setup_theme_tab(notebook) self.__setup_appearance_tab(notebook)
self.__setup_plugin_tab(notebook) self.__setup_plugin_tab(notebook)
if platform == 'darwin': if platform == 'darwin':
@ -287,8 +331,8 @@ class PreferencesDialog(tk.Toplevel):
self.geometry(f"+{position.left}+{position.top}") self.geometry(f"+{position.left}+{position.top}")
def __setup_output_tab(self, root_notebook: nb.Notebook) -> None: def __setup_output_tab(self, root_notebook: nb.Notebook) -> None:
outframe = nb.Frame(root_notebook) output_frame = nb.Frame(root_notebook)
outframe.columnconfigure(0, weight=1) output_frame.columnconfigure(0, weight=1)
if prefsVersion.shouldSetDefaults('0.0.0.0', not bool(config.getint('output'))): if prefsVersion.shouldSetDefaults('0.0.0.0', not bool(config.getint('output'))):
output = config.OUT_SHIP # default settings output = config.OUT_SHIP # default settings
@ -296,157 +340,151 @@ class PreferencesDialog(tk.Toplevel):
else: else:
output = config.getint('output') output = config.getint('output')
row = 0 row = AutoInc(start=1)
# 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 # adding one to keep track, so it's easier to insert new rows in
# the middle without worrying about updating `row=X` elements. # 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 = 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) self.out_label.grid(columnspan=2, padx=self.PADX, sticky=tk.W, row=row.get())
row += 1
self.out_csv = tk.IntVar(value=1 if (output & config.OUT_MKT_CSV) else 0) self.out_csv = tk.IntVar(value=1 if (output & config.OUT_MKT_CSV) else 0)
self.out_csv_button = nb.Checkbutton( self.out_csv_button = nb.Checkbutton(
outframe, output_frame,
text=_('Market data in CSV format file'), text=_('Market data in CSV format file'),
variable=self.out_csv, variable=self.out_csv,
command=self.outvarchanged command=self.outvarchanged
) )
self.out_csv_button.grid(columnspan=2, padx=self.BUTTONX, sticky=tk.W, row=row) self.out_csv_button.grid(columnspan=2, padx=self.BUTTONX, sticky=tk.W, row=row.get())
row += 1
self.out_td = tk.IntVar(value=1 if (output & config.OUT_MKT_TD) else 0) self.out_td = tk.IntVar(value=1 if (output & config.OUT_MKT_TD) else 0)
self.out_td_button = nb.Checkbutton( self.out_td_button = nb.Checkbutton(
outframe, output_frame,
text=_('Market data in Trade Dangerous format file'), text=_('Market data in Trade Dangerous format file'),
variable=self.out_td, variable=self.out_td,
command=self.outvarchanged 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) self.out_ship = tk.IntVar(value=1 if (output & config.OUT_SHIP) else 0)
row += 1
# Output setting # Output setting
self.out_ship_button = nb.Checkbutton( self.out_ship_button = nb.Checkbutton(
outframe, output_frame,
text=_('Ship loadout'), text=_('Ship loadout'),
variable=self.out_ship, variable=self.out_ship,
command=self.outvarchanged 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 self.out_auto = tk.IntVar(value=0 if output & config.OUT_MKT_MANUAL else 1) # inverted
row += 1
# Output setting # Output setting
self.out_auto_button = nb.Checkbutton( self.out_auto_button = nb.Checkbutton(
outframe, output_frame,
text=_('Automatically update on docking'), text=_('Automatically update on docking'),
variable=self.out_auto, variable=self.out_auto,
command=self.outvarchanged 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=self.BUTTONX, pady=(5, 0), sticky=tk.W, row=row.get())
row += 1
self.outdir = tk.StringVar() self.outdir = tk.StringVar()
self.outdir.set(str(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 = nb.Label(output_frame, 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 # 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(output_frame, takefocus=False)
self.outdir_entry.grid(columnspan=2, padx=self.PADX, pady=(0, self.PADY), sticky=tk.EW, row=row.get())
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)
row += 1
self.outbutton = nb.Button( self.outbutton = nb.Button(
outframe, output_frame,
text=(_('Change...') if platform == 'darwin' else _('Browse...')), text=(_('Change...') if platform == 'darwin' else _('Browse...')),
command=lambda: self.filebrowse(_('File location'), self.outdir) 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(output_frame).grid(row=row.get()) # bottom spacer # TODO: does nothing?
nb.Frame(outframe).grid(row=row) # bottom spacer # TODO: does nothing? root_notebook.add(output_frame, text=_('Output')) # Tab heading in settings
root_notebook.add(outframe, text=_('Output')) # Tab heading in settings
def __setup_plugin_tabs(self, notebook: Notebook) -> None: def __setup_plugin_tabs(self, notebook: Notebook) -> None:
for plugin in plug.PLUGINS: for plugin in plug.PLUGINS:
plugframe = plugin.get_prefs(notebook, monitor.cmdr, monitor.is_beta) plugin_frame = plugin.get_prefs(notebook, monitor.cmdr, monitor.is_beta)
if plugframe: if plugin_frame:
notebook.add(plugframe, text=plugin.name) notebook.add(plugin_frame, text=plugin.name)
def __setup_config_tab(self, notebook: Notebook) -> None: def __setup_config_tab(self, notebook: Notebook) -> None:
configframe = nb.Frame(notebook) config_frame = nb.Frame(notebook)
configframe.columnconfigure(1, weight=1) config_frame.columnconfigure(1, weight=1)
row = AutoInc(start=1)
self.logdir = tk.StringVar() self.logdir = tk.StringVar()
self.logdir.set(str(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) self.logdir_entry = nb.Entry(config_frame, takefocus=False)
# Location of the new Journal file in E:D 2.2 # Location of the new Journal file in E:D 2.2
nb.Label( nb.Label(
configframe, config_frame,
text=_('E:D journal file location')+':' 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( self.logbutton = nb.Button(
configframe, config_frame,
text=(_('Change...') if platform == 'darwin' else _('Browse...')), text=(_('Change...') if platform == 'darwin' else _('Browse...')),
command=lambda: self.filebrowse(_('E:D journal file location'), self.logdir) 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: if config.default_journal_dir:
# Appearance theme and language setting # Appearance theme and language setting
nb.Button( nb.Button(
configframe, config_frame,
text=_('Default'), text=_('Default'),
command=self.logdir_reset, command=self.logdir_reset,
state=tk.NORMAL if config.get('journaldir') else tk.DISABLED 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_code = config.getint('hotkey_code')
self.hotkey_mods = config.getint('hotkey_mods') self.hotkey_mods = config.getint('hotkey_mods')
self.hotkey_only = tk.IntVar(value=not config.getint('hotkey_always')) self.hotkey_only = tk.IntVar(value=not config.getint('hotkey_always'))
self.hotkey_play = tk.IntVar(value=not config.getint('hotkey_mute')) self.hotkey_play = tk.IntVar(value=not config.getint('hotkey_mute'))
nb.Label( nb.Label(
configframe, config_frame,
text=_('Keyboard shortcut') if # Hotkey/Shortcut settings prompt on OSX text=_('Keyboard shortcut') if # Hotkey/Shortcut settings prompt on OSX
platform == 'darwin' else platform == 'darwin' else
_('Hotkey') # Hotkey/Shortcut settings prompt on Windows _('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 platform == 'darwin' and not was_accessible_at_launch:
if AXIsProcessTrusted(): if AXIsProcessTrusted():
nb.Label(configframe, text=_('Re-start {APP} to use shortcuts').format(APP=applongname), # Shortcut settings prompt on OSX
foreground='firebrick').grid(padx=self.PADX, sticky=tk.W) # 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: else:
# Shortcut settings prompt on OSX # Shortcut settings prompt on OSX
nb.Label( nb.Label(
configframe, config_frame,
text=_('{APP} needs permission to use shortcuts').format( text=_('{APP} needs permission to use shortcuts').format(APP=applongname),
APP=applongname
),
foreground='firebrick' 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( # Shortcut settings button on OSX
padx=self.PADX, sticky=tk.E) # 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: 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( self.hotkey_text.insert(
0, 0,
# No hotkey/shortcut currently defined # No hotkey/shortcut currently defined
@ -456,132 +494,149 @@ class PreferencesDialog(tk.Toplevel):
self.hotkey_text.bind('<FocusIn>', self.hotkeystart) self.hotkey_text.bind('<FocusIn>', self.hotkeystart)
self.hotkey_text.bind('<FocusOut>', self.hotkeyend) self.hotkey_text.bind('<FocusOut>', 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 # Hotkey/Shortcut setting
self.hotkey_only_btn = nb.Checkbutton( self.hotkey_only_btn = nb.Checkbutton(
configframe, config_frame,
text=_('Only when Elite: Dangerous is the active app'), text=_('Only when Elite: Dangerous is the active app'),
variable=self.hotkey_only, variable=self.hotkey_only,
state=tk.NORMAL if self.hotkey_code else tk.DISABLED 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 # Hotkey/Shortcut setting
self.hotkey_play_btn = nb.Checkbutton( self.hotkey_play_btn = nb.Checkbutton(
configframe, config_frame,
text=_('Play sound'), text=_('Play sound'),
variable=self.hotkey_play, variable=self.hotkey_play,
state=tk.NORMAL if self.hotkey_code else tk.DISABLED 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 # 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 = tk.IntVar(value=config.getint('disable_autoappupdatecheckingame'))
self.disable_autoappupdatecheckingame_btn = nb.Checkbutton( self.disable_autoappupdatecheckingame_btn = nb.Checkbutton(
configframe, config_frame,
text=_('Disable Automatic Application Updates Check when in-game'), text=_('Disable Automatic Application Updates Check when in-game'),
variable=self.disable_autoappupdatecheckingame, variable=self.disable_autoappupdatecheckingame,
command=self.disable_autoappupdatecheckingame_changed 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(config_frame, orient=tk.HORIZONTAL).grid(
columnspan=4, padx=self.PADX, pady=self.PADY*4, sticky=tk.EW, row=row.get()
)
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 # 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) nb.Label(config_frame, text=_('Preferred websites')).grid(
columnspan=4, padx=self.PADX, sticky=tk.W, row=row.get()
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')
) )
self.shipyard_button.configure(width=15) with row as cur_row:
self.shipyard_button.grid(row=31, column=1, sticky=tk.W) self.shipyard_provider = tk.StringVar(
# Option for alternate URL opening value=str(
self.alt_shipyard_open = tk.IntVar(value=config.getint('use_alt_shipyard_open')) config.get('shipyard_provider') in plug.provides('shipyard_url')
self.alt_shipyard_open_btn = nb.Checkbutton( and config.get('shipyard_provider') or 'EDSY')
configframe, )
text=_('Use alternate URL method'), # Setting to decide which ship outfitting website to link to - either E:D Shipyard or Coriolis
variable=self.alt_shipyard_open, nb.Label(config_frame, text=_('Shipyard')).grid(padx=self.PADX, pady=2*self.PADY, sticky=tk.W, row=cur_row)
command=self.alt_shipyard_open_changed, 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.alt_shipyard_open_btn.grid(column=2, sticky=tk.W, row=cur_row)
self.system_provider = tk.StringVar(
value=str(system_provider if system_provider in plug.provides('system_url') else 'EDSM')
)
nb.Label(configframe, text=_('System')).grid(row=32, padx=self.PADX, pady=2*self.PADY, sticky=tk.W) with row as cur_row:
self.system_button = nb.OptionMenu( system_provider = config.get('system_provider')
configframe, self.system_provider = tk.StringVar(
self.system_provider, value=str(system_provider if system_provider in plug.provides('system_url') else 'EDSM')
self.system_provider.get(), )
*plug.provides('system_url')
)
self.system_button.configure(width=15) nb.Label(config_frame, text=_('System')).grid(padx=self.PADX, pady=2*self.PADY, sticky=tk.W, row=cur_row)
self.system_button.grid(row=32, column=1, sticky=tk.W) 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.system_button.configure(width=15)
self.station_provider = tk.StringVar( self.system_button.grid(column=1, sticky=tk.W, row=cur_row)
value=str(station_provider if station_provider in plug.provides('station_url') else 'eddb')
)
nb.Label(configframe, text=_('Station')).grid(row=33, padx=self.PADX, pady=2*self.PADY, sticky=tk.W) with row as cur_row:
self.station_button = nb.OptionMenu( station_provider = config.get('station_provider')
configframe, self.station_provider = tk.StringVar(
self.station_provider, value=str(station_provider if station_provider in plug.provides('station_url') else 'eddb')
self.station_provider.get(), )
*plug.provides('station_url')
)
self.station_button.configure(width=15) nb.Label(config_frame, text=_('Station')).grid(padx=self.PADX, pady=2*self.PADY, sticky=tk.W, row=cur_row)
self.station_button.grid(row=33, column=1, sticky=tk.W) 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 # Set loglevel
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()
# 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))
) )
self.loglevel_dropdown = nb.OptionMenu( with row as cur_row:
configframe, # Set the current loglevel
self.select_loglevel, nb.Label(
self.select_loglevel.get(), config_frame,
*loglevels text=_('Log Level')
) ).grid(padx=self.PADX, pady=2*self.PADY, sticky=tk.W, row=cur_row)
self.loglevel_dropdown.configure(width=15) current_loglevel = config.get('loglevel')
self.loglevel_dropdown.grid(row=35, column=1, sticky=tk.W) 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 # 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() self.languages = Translations.available_names()
# Appearance theme and language setting # Appearance theme and language setting
self.lang = tk.StringVar(value=self.languages.get(config.get('language'), _('Default'))) 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 _('Highlighted text'), # Dark theme color setting
] ]
def __setup_theme_tab(self, notebook: Notebook) -> None: row = AutoInc(start=1)
themeframe = nb.Frame(notebook)
themeframe.columnconfigure(2, weight=1) appearance_frame = nb.Frame(notebook)
nb.Label(themeframe, text=_('Language')).grid(row=10, padx=self.PADX, sticky=tk.W) # Appearance setting prompt appearance_frame.columnconfigure(2, weight=1)
self.lang_button = nb.OptionMenu(themeframe, self.lang, self.lang.get(), *self.languages.values()) with row as cur_row:
self.lang_button.grid(row=10, column=1, columnspan=2, padx=self.PADX, sticky=tk.W) nb.Label(appearance_frame, text=_('Language')).grid(padx=self.PADX, sticky=tk.W, row=cur_row)
ttk.Separator(themeframe, orient=tk.HORIZONTAL).grid(columnspan=3, padx=self.PADX, pady=self.PADY*4, sticky=tk.EW) self.lang_button = nb.OptionMenu(appearance_frame, self.lang, self.lang.get(), *self.languages.values())
nb.Label(themeframe, text=_('Theme')).grid(columnspan=3, padx=self.PADX, sticky=tk.W) # Appearance setting self.lang_button.grid(column=1, columnspan=2, padx=self.PADX, sticky=tk.W, row=cur_row)
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 ttk.Separator(appearance_frame, orient=tk.HORIZONTAL).grid(
nb.Radiobutton(themeframe, text=_('Dark'), variable=self.theme, value=1, command=self.themevarchanged).grid( columnspan=3, padx=self.PADX, pady=self.PADY*4, sticky=tk.EW, row=row.get()
columnspan=3, padx=self.BUTTONX, sticky=tk.W) # Appearance theme setting )
# 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': if platform == 'win32':
nb.Radiobutton( nb.Radiobutton(
themeframe, appearance_frame,
text=_('Transparent'), # Appearance theme setting text=_('Transparent'), # Appearance theme setting
variable=self.theme, variable=self.theme,
value=2, value=2,
command=self.themevarchanged 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]) with row as cur_row:
self.theme_label_0.grid(row=20, padx=self.PADX, sticky=tk.W) 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 # Main window
self.theme_button_0 = nb.ColoredButton( self.theme_button_0 = nb.ColoredButton(
themeframe, appearance_frame,
text=_('Station'), text=_('Station'),
background='grey4', background='grey4',
command=lambda: self.themecolorbrowse(0) 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_button_0.grid(column=1, padx=self.PADX, pady=self.PADY, sticky=tk.NSEW, row=cur_row)
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_1.grid(row=21, column=1, padx=self.PADX, pady=self.PADY, sticky=tk.NSEW) 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(column=1, padx=self.PADX, pady=self.PADY, sticky=tk.NSEW, row=cur_row)
# UI Scaling # 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 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. 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) ttk.Separator(appearance_frame, orient=tk.HORIZONTAL).grid(
nb.Label(themeframe, text=_('UI Scale Percentage')).grid(row=23, padx=self.PADX, pady=2*self.PADY, sticky=tk.W) columnspan=4, padx=self.PADX, pady=self.PADY*4, sticky=tk.EW, row=row.get()
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,
) )
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_scale = tk.IntVar()
self.ui_scaling_defaultis = nb.Label( self.ui_scale.set(config.getint('ui_scale'))
themeframe, self.uiscale_bar = tk.Scale(
text=_('100 means Default{CR}Restart Required for{CR}changes to take effect!') appearance_frame,
).grid(row=23, column=3, padx=PADX, pady=2*PADY, sticky=tk.E) 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 # 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( self.ontop_button = nb.Checkbutton(
themeframe, appearance_frame,
text=_('Always on top'), text=_('Always on top'),
variable=self.always_ontop, variable=self.always_ontop,
command=self.themevarchanged 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) # Appearance setting nb.Label(appearance_frame).grid(sticky=tk.W) # big spacer
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: def __setup_plugin_tab(self, notebook: Notebook) -> None:
# Plugin tab itself # Plugin tab itself
# Plugin settings and info # Plugin settings and info
plugsframe = nb.Frame(notebook) plugins_frame = nb.Frame(notebook)
plugsframe.columnconfigure(0, weight=1) plugins_frame.columnconfigure(0, weight=1)
plugdir = tk.StringVar() plugdir = tk.StringVar()
plugdir.set(config.plugin_dir) 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 # Section heading in settings
plugdirentry = nb.Entry(plugsframe, justify=tk.LEFT) 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) 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( nb.Button(
plugsframe, plugins_frame,
text=_('Open'), # Button that opens a folder in Explorer/Finder text=_('Open'), # Button that opens a folder in Explorer/Finder
command=lambda: webbrowser.open(f'file:///{plugdir.get()}') command=lambda: webbrowser.open(f'file:///{plugdir.get()}')
).grid(row=10, column=1, padx=(0, self.PADX), sticky=tk.NSEW) ).grid(column=1, padx=(0, self.PADX), sticky=tk.NSEW, row=cur_row)
nb.Label( nb.Label(
plugsframe, plugins_frame,
# Help text in settings # Help text in settings
text=_("Tip: You can disable a plugin by{CR}adding '{EXT}' to its folder name").format(EXT='.disabled') 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)) enabled_plugins = list(filter(lambda x: x.folder and x.module, plug.PLUGINS))
if len(enabled_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( nb.Label(
plugsframe, plugins_frame,
text=_('Enabled Plugins')+':' # List of plugins in settings 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: for plugin in enabled_plugins:
if plugin.name == plugin.folder: if plugin.name == plugin.folder:
label = nb.Label(plugsframe, text=plugin.name) label = nb.Label(plugins_frame, text=plugin.name)
else: 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 # Show which plugins don't have Python 3.x support
############################################################ ############################################################
if len(plug.PLUGINS_not_py3): 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) ttk.Separator(plugins_frame, orient=tk.HORIZONTAL).grid(
nb.Label(plugsframe, text=_('Plugins Without Python 3.x Support:')+':').grid(padx=self.PADX, sticky=tk.W) 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: 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=self.PADX*2, sticky=tk.W) nb.Label(plugins_frame, text=plugin.name).grid(columnspan=2, padx=self.PADX*2, sticky=tk.W)
HyperlinkLabel( HyperlinkLabel(
plugsframe, text=_('Information on migrating plugins'), plugins_frame, text=_('Information on migrating plugins'),
background=nb.Label().cget('background'), background=nb.Label().cget('background'),
url='https://github.com/EDCD/EDMarketConnector/blob/main/PLUGINS.md#migration-to-python-37', url='https://github.com/EDCD/EDMarketConnector/blob/main/PLUGINS.md#migration-to-python-37',
underline=True underline=True
@ -744,16 +828,20 @@ class PreferencesDialog(tk.Toplevel):
disabled_plugins = list(filter(lambda x: x.folder and not x.module, plug.PLUGINS)) disabled_plugins = list(filter(lambda x: x.folder and not x.module, plug.PLUGINS))
if len(disabled_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( nb.Label(
plugsframe, plugins_frame,
text=_('Disabled Plugins')+':' # List of plugins in settings 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: 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): def cmdrchanged(self, event=None):
""" """