From c3f9247cd11b2bc044ea5af31fdf9b3c53f7c924 Mon Sep 17 00:00:00 2001 From: David Sangrey Date: Tue, 11 Nov 2025 20:24:58 -0500 Subject: [PATCH 1/6] [#2116] Hand more things to TTK --- myNotebook.py | 32 ++++++++++----------- outfitting.py | 4 +-- plugins/eddn.py | 55 +++++++++++++++++++------------------ plugins/inara.py | 6 ++-- stats.py | 2 +- tests/config/test_config.py | 4 +-- 6 files changed, 51 insertions(+), 52 deletions(-) diff --git a/myNotebook.py b/myNotebook.py index 02a7bef6..b488916a 100644 --- a/myNotebook.py +++ b/myNotebook.py @@ -41,23 +41,23 @@ class Frame(ttk.Frame): """Custom ttk.Frame class to fix some display issues.""" def __init__(self, master: ttk.Notebook | None = None, **kw): - if sys.platform == 'win32': - ttk.Frame.__init__(self, master, style='nb.TFrame', **kw) - ttk.Frame(self).grid(pady=5) # top spacer - else: - ttk.Frame.__init__(self, master, **kw) - ttk.Frame(self).grid(pady=5) # top spacer - self.configure(takefocus=1) # let the frame take focus so that no particular child is focused + style = 'nb.TFrame' if sys.platform == 'win32' else None + super().__init__(master, style=style, **kw) # type: ignore + ttk.Frame(self).grid(pady=5) # Top spacer + self.configure(takefocus=1) # let the frame take focus so that no particular child is focused -class Label(tk.Label): - """Custom tk.Label class to fix some display issues.""" +class Label(ttk.Label): + """Custom ttk.Label class to fix some display issues.""" def __init__(self, master: ttk.Frame | None = None, **kw): - kw['foreground'] = kw.pop('foreground', PAGEFG if sys.platform == 'win32' - else ttk.Style().lookup('TLabel', 'foreground')) - kw['background'] = kw.pop('background', PAGEBG if sys.platform == 'win32' - else ttk.Style().lookup('TLabel', 'background')) + style = ttk.Style() + if sys.platform == 'win32': + custom_style = 'nb.TLabel' # Create or update a style to emulate the tk.Label colors + style.configure(custom_style, foreground=PAGEFG, background=PAGEBG) + else: + custom_style = 'TLabel' # Use the platform default ttk style + kw.setdefault('style', custom_style) super().__init__(master, **kw) @@ -134,10 +134,8 @@ class Button(ttk.Button): """Custom ttk.Button class to fix some display issues.""" def __init__(self, master: ttk.Frame | None = None, **kw): - if sys.platform == 'win32': - ttk.Button.__init__(self, master, style='nb.TButton', **kw) - else: - ttk.Button.__init__(self, master, **kw) + style = 'nb.TButton' if sys.platform == 'win32' else None + super().__init__(master, style=style, **kw) # type: ignore class ColoredButton(tk.Button): diff --git a/outfitting.py b/outfitting.py index 207c4883..4b014e48 100644 --- a/outfitting.py +++ b/outfitting.py @@ -302,8 +302,8 @@ def export(data, filename) -> None: try: m = lookup(v, ship_name_map) if m: - h.write(f'{rowheader}, {m["category"]}, {m["name"]}, {m.get("mount","")},' - f'{m.get("guidance","")}, {m.get("ship","")}, {m["class"]}, {m["rating"]},' + h.write(f'{rowheader}, {m["category"]}, {m["name"]}, {m.get("mount", "")},' + f'{m.get("guidance", "")}, {m.get("ship", "")}, {m["class"]}, {m["rating"]},' f'{m["id"]}, {data["timestamp"]}\n') except ValueError as e: diff --git a/plugins/eddn.py b/plugins/eddn.py index bdf0c96e..2e37e1bf 100644 --- a/plugins/eddn.py +++ b/plugins/eddn.py @@ -29,6 +29,7 @@ import pathlib import re import sqlite3 import tkinter as tk +from tkinter import ttk import warnings from platform import system from textwrap import dedent @@ -115,15 +116,15 @@ class This: # Tracking UI self.ui: tk.Frame - self.ui_system_name: tk.Label - self.ui_system_address: tk.Label - self.ui_j_body_name: tk.Label - self.ui_j_body_id: tk.Label - self.ui_j_body_type: tk.Label - self.ui_s_body_name: tk.Label - self.ui_station_name: tk.Label - self.ui_station_type: tk.Label - self.ui_station_marketid: tk.Label + self.ui_system_name: ttk.Label + self.ui_system_address: ttk.Label + self.ui_j_body_name: ttk.Label + self.ui_j_body_id: ttk.Label + self.ui_j_body_type: ttk.Label + self.ui_s_body_name: ttk.Label + self.ui_station_name: ttk.Label + self.ui_station_type: ttk.Label + self.ui_station_marketid: ttk.Label this = This() @@ -2027,15 +2028,15 @@ def plugin_app(parent: tk.Tk) -> tk.Frame | None: # System ####################################################################### # SystemName - system_name_label = tk.Label(this.ui, text="J:SystemName:") + system_name_label = ttk.Label(this.ui, text="J:SystemName:") system_name_label.grid(row=row, column=0, sticky=tk.W) - this.ui_system_name = tk.Label(this.ui, name='eddn_track_system_name', anchor=tk.W) + this.ui_system_name = ttk.Label(this.ui, name='eddn_track_system_name', anchor=tk.W) this.ui_system_name.grid(row=row, column=1, sticky=tk.E) row += 1 # SystemAddress - system_address_label = tk.Label(this.ui, text="J:SystemAddress:") + system_address_label = ttk.Label(this.ui, text="J:SystemAddress:") system_address_label.grid(row=row, column=0, sticky=tk.W) - this.ui_system_address = tk.Label(this.ui, name='eddn_track_system_address', anchor=tk.W) + this.ui_system_address = ttk.Label(this.ui, name='eddn_track_system_address', anchor=tk.W) this.ui_system_address.grid(row=row, column=1, sticky=tk.E) row += 1 ####################################################################### @@ -2044,27 +2045,27 @@ def plugin_app(parent: tk.Tk) -> tk.Frame | None: # Body ####################################################################### # Body Name from Journal - journal_body_name_label = tk.Label(this.ui, text="J:BodyName:") + journal_body_name_label = ttk.Label(this.ui, text="J:BodyName:") journal_body_name_label.grid(row=row, column=0, sticky=tk.W) - this.ui_j_body_name = tk.Label(this.ui, name='eddn_track_j_body_name', anchor=tk.W) + this.ui_j_body_name = ttk.Label(this.ui, name='eddn_track_j_body_name', anchor=tk.W) this.ui_j_body_name.grid(row=row, column=1, sticky=tk.E) row += 1 # Body ID from Journal - journal_body_id_label = tk.Label(this.ui, text="J:BodyID:") + journal_body_id_label = ttk.Label(this.ui, text="J:BodyID:") journal_body_id_label.grid(row=row, column=0, sticky=tk.W) - this.ui_j_body_id = tk.Label(this.ui, name='eddn_track_j_body_id', anchor=tk.W) + this.ui_j_body_id = ttk.Label(this.ui, name='eddn_track_j_body_id', anchor=tk.W) this.ui_j_body_id.grid(row=row, column=1, sticky=tk.E) row += 1 # Body Type from Journal - journal_body_type_label = tk.Label(this.ui, text="J:BodyType:") + journal_body_type_label = ttk.Label(this.ui, text="J:BodyType:") journal_body_type_label.grid(row=row, column=0, sticky=tk.W) - this.ui_j_body_type = tk.Label(this.ui, name='eddn_track_j_body_type', anchor=tk.W) + this.ui_j_body_type = ttk.Label(this.ui, name='eddn_track_j_body_type', anchor=tk.W) this.ui_j_body_type.grid(row=row, column=1, sticky=tk.E) row += 1 # Body Name from Status.json - status_body_name_label = tk.Label(this.ui, text="S:BodyName:") + status_body_name_label = ttk.Label(this.ui, text="S:BodyName:") status_body_name_label.grid(row=row, column=0, sticky=tk.W) - this.ui_s_body_name = tk.Label(this.ui, name='eddn_track_s_body_name', anchor=tk.W) + this.ui_s_body_name = ttk.Label(this.ui, name='eddn_track_s_body_name', anchor=tk.W) this.ui_s_body_name.grid(row=row, column=1, sticky=tk.E) row += 1 ####################################################################### @@ -2073,21 +2074,21 @@ def plugin_app(parent: tk.Tk) -> tk.Frame | None: # Station ####################################################################### # Name - status_station_name_label = tk.Label(this.ui, text="J:StationName:") + status_station_name_label = ttk.Label(this.ui, text="J:StationName:") status_station_name_label.grid(row=row, column=0, sticky=tk.W) - this.ui_station_name = tk.Label(this.ui, name='eddn_track_station_name', anchor=tk.W) + this.ui_station_name = ttk.Label(this.ui, name='eddn_track_station_name', anchor=tk.W) this.ui_station_name.grid(row=row, column=1, sticky=tk.E) row += 1 # Type - status_station_type_label = tk.Label(this.ui, text="J:StationType:") + status_station_type_label = ttk.Label(this.ui, text="J:StationType:") status_station_type_label.grid(row=row, column=0, sticky=tk.W) - this.ui_station_type = tk.Label(this.ui, name='eddn_track_station_type', anchor=tk.W) + this.ui_station_type = ttk.Label(this.ui, name='eddn_track_station_type', anchor=tk.W) this.ui_station_type.grid(row=row, column=1, sticky=tk.E) row += 1 # MarketID - status_station_marketid_label = tk.Label(this.ui, text="J:StationID:") + status_station_marketid_label = ttk.Label(this.ui, text="J:StationID:") status_station_marketid_label.grid(row=row, column=0, sticky=tk.W) - this.ui_station_marketid = tk.Label(this.ui, name='eddn_track_station_id', anchor=tk.W) + this.ui_station_marketid = ttk.Label(this.ui, name='eddn_track_station_id', anchor=tk.W) this.ui_station_marketid.grid(row=row, column=1, sticky=tk.E) row += 1 ####################################################################### diff --git a/plugins/inara.py b/plugins/inara.py index 7bc31a30..e398a3f3 100644 --- a/plugins/inara.py +++ b/plugins/inara.py @@ -122,11 +122,11 @@ class This: self.station_marketid = None # Prefs UI - self.log: 'tk.IntVar' + self.log: tk.IntVar self.log_button: nb.Checkbutton self.label: HyperlinkLabel self.apikey: nb.EntryMenu - self.apikey_label: tk.Label + self.apikey_label: ttk.Label self.events: dict[Credentials, Deque[Event]] = defaultdict(deque) self.event_lock: Lock = threading.Lock() # protects events, for use when rewriting events @@ -1610,7 +1610,7 @@ def handle_api_error(data: Mapping[str, Any], status: int, reply: dict[str, Any] """ error_message = reply['header'].get('eventStatusText', "") logger.warning(f'Inara\t{status} {error_message}') - logger.debug(f'JSON data:\n{json.dumps(data, indent=2, separators = (",", ": "))}') + logger.debug(f'JSON data:\n{json.dumps(data, indent=2, separators=(",", ": "))}') # LANG: INARA API returned some kind of error (error message will be contained in {MSG}) plug.show_error(tr.tl('Error: Inara {MSG}').format(MSG=error_message)) diff --git a/stats.py b/stats.py index 4c4b0e3d..c16ec880 100644 --- a/stats.py +++ b/stats.py @@ -457,7 +457,7 @@ class StatsResults(tk.Toplevel): # label = HyperlinkLabel(parent, text=col_content, popup_copy=True) label = nb.Label(parent, text=col_content) if with_copy: - label.bind('', self.copy_callback(label, col_content)) + label.bind('', self.copy_callback(label, col_content)) # type: ignore if i == 0: label.grid(padx=10, sticky=tk.W) diff --git a/tests/config/test_config.py b/tests/config/test_config.py index e839afc7..642da5c2 100644 --- a/tests/config/test_config.py +++ b/tests/config/test_config.py @@ -117,7 +117,7 @@ class TestNewConfig: @mark.parametrize("lst", _build_test_list(list_tests, _get_fuzz(list))) def test_list(self, lst: list[str]) -> None: """Save a list and then ask for it back.""" - name = f'list_test_{ hash("".join(lst)) }' + name = f'list_test_{hash("".join(lst))}' config.set(name, lst) config.save() @@ -222,7 +222,7 @@ class TestOldNewConfig: # So insert those spaces here, to ensure that it works otherwise. lst = [e if len(e) > 0 else ' ' for e in lst] - name = self.KEY_PREFIX + f'list_test_{ hash("".join(lst)) }' + name = self.KEY_PREFIX + f'list_test_{hash("".join(lst))}' old_config.set(name, lst) old_config.save() From 29784a3e78e2bc1538742f7b7181961c9a5b73a4 Mon Sep 17 00:00:00 2001 From: David Sangrey Date: Tue, 11 Nov 2025 20:31:50 -0500 Subject: [PATCH 2/6] [Docs] Update Documentation --- docs/Releasing.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/Releasing.md b/docs/Releasing.md index 1edc281c..033f0a2b 100644 --- a/docs/Releasing.md +++ b/docs/Releasing.md @@ -38,8 +38,8 @@ You will need several pieces of software installed, or the files from their auto-select some others). NB: If you have need to uninstall this it's "Windows Software Development Kit - Windows 10.0.19041.1" in "Apps & Features", *not* "Windows SDK AddOn". -1. [Python](https://python.org): 32-bit version of Python 3.10 for Windows. - [v3.10.3](https://www.python.org/downloads/release/python-3103/) is the most +1. [Python](https://python.org): 32-bit version of Python 3.13 for Windows. + [v3.13.9](https://www.python.org/downloads/release/python-3139/) is the most recently tested version. You need the `Windows x86 executable installer` file, for the 32-bit version. Double-check the version against the `.python.version` file, as it should always contain the intended version. From 0994f1351b3763c0baf24ec026393d3bcc755b66 Mon Sep 17 00:00:00 2001 From: David Sangrey Date: Tue, 11 Nov 2025 21:47:02 -0500 Subject: [PATCH 3/6] [#2440] Refactor Updater --- update.py | 199 +++++++++++++++++++++++++++--------------------------- 1 file changed, 98 insertions(+), 101 deletions(-) diff --git a/update.py b/update.py index f9574242..7ea619b8 100644 --- a/update.py +++ b/update.py @@ -12,9 +12,10 @@ import shutil import sys import threading import os +from dataclasses import dataclass from tkinter import messagebox from traceback import print_exc -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, cast, Any from xml.etree import ElementTree import requests import semantic_version @@ -25,58 +26,68 @@ from l10n import translations as tr if TYPE_CHECKING: import tkinter as tk - logger = get_main_logger() -def check_for_fdev_updates(silent: bool = False, local: bool = False) -> None: # noqa: CCR001 +def read_normalized_file(path: pathlib.Path) -> str: + """Read a UTF-8 (with BOM-safe) file and normalize line endings and whitespace.""" + try: + return path.read_bytes().decode('utf-8-sig').replace('\r\n', '\n').strip() + except FileNotFoundError: + return '' + + +def copy_bundle_file(filename: str, dest_dir: pathlib.Path) -> str: + """Attempt to copy a missing file from the bundled FDevIDs folder.""" + try: + shutil.copy(f"FDevIDs/{filename}", dest_dir) + return read_normalized_file(dest_dir / filename) + except (FileNotFoundError, shutil.SameFileError): + logger.info("Bundle copy failed or identical; continuing with empty content.") + return '' + + +def fetch_remote_file(url: str) -> str | None: + """Fetch a remote file and normalize its content.""" + try: + response = requests.get(url, timeout=20) + response.raise_for_status() + return response.text.replace('\r\n', '\n').strip() + except requests.RequestException: + return None + + +def check_for_fdev_updates(silent: bool = False, local: bool = False) -> None: """Check for and download FDEV ID file updates.""" - pathway = config.respath_path if local else config.app_dir_path + base_path = config.respath_path if local else config.app_dir_path + fdevid_dir = pathlib.Path(base_path, 'FDevIDs') + fdevid_dir.mkdir(parents=True, exist_ok=True) - files_urls = [ - ('commodity.csv', 'https://raw.githubusercontent.com/EDCD/FDevIDs/master/commodity.csv'), - ('rare_commodity.csv', 'https://raw.githubusercontent.com/EDCD/FDevIDs/master/rare_commodity.csv') - ] + files_urls = { + 'commodity.csv': 'https://raw.githubusercontent.com/EDCD/FDevIDs/master/commodity.csv', + 'rare_commodity.csv': 'https://raw.githubusercontent.com/EDCD/FDevIDs/master/rare_commodity.csv' + } - for file, url in files_urls: - fdevid_file = pathlib.Path(pathway / 'FDevIDs' / file) - fdevid_file.parent.mkdir(parents=True, exist_ok=True) - try: - with open(fdevid_file, newline='', encoding='utf-8') as f: - local_content = f.read() - except FileNotFoundError: - logger.info(f'File {file} not found. Writing from bundle...') - try: - for localfile in files_urls: - filepath = pathlib.Path(f"FDevIDs/{localfile[0]}") - try: - shutil.copy(filepath, pathway / 'FDevIDs') - except shutil.SameFileError: - logger.info("Not replacing same file...") - fdevid_file = pathlib.Path(pathway / 'FDevIDs' / file) - with open(fdevid_file, newline='', encoding='utf-8') as f: - local_content = f.read() - except FileNotFoundError: - local_content = None - - try: - response = requests.get(url, timeout=20) - response.raise_for_status() - except requests.RequestException: + for filename, url in files_urls.items(): + file_path = fdevid_dir / filename + local_content = read_normalized_file(file_path) or copy_bundle_file(filename, fdevid_dir) + remote_content = fetch_remote_file(url) + if not remote_content: if not silent: - logger.error(f'Failed to download {file}! Unable to continue.') + logger.error(f'Failed to download {filename}! Unable to continue.') continue - if local_content == response.text: + if local_content == remote_content: if not silent: - logger.info(f'FDEV ID file {file} already up to date.') - else: - if not silent: - logger.info(f'FDEV ID file {file} not up to date. Downloading...') - with open(fdevid_file, 'w', newline='', encoding='utf-8') as csvfile: - csvfile.write(response.text) + logger.info(f'FDEV ID file {filename} already up to date.') + continue + + if not silent: + logger.info(f'Updating FDEV ID file {filename}...') + file_path.write_text(remote_content, encoding='utf-8', newline='\n') +@dataclass(slots=True) class EDMCVersion: """ Hold all the information about an EDMC version. @@ -91,10 +102,9 @@ class EDMCVersion: semantic_version object for this version """ - def __init__(self, version: str, title: str, sv: semantic_version.base.Version): - self.version: str = version - self.title: str = title - self.sv: semantic_version.base.Version = sv + version: str + title: str + sv: semantic_version.Version class Updater: @@ -105,6 +115,21 @@ class Updater: WinSparkle on win32. """ + def __init__(self, tkroot: tk.Tk | None = None, provider: str = 'internal'): + """ + Initialise an Updater instance. + + :param tkroot: reference to the root window of the GUI + :param provider: 'internal' or other string if not + """ + self.root: tk.Tk | None = tkroot + self.provider: str = provider + self.thread: threading.Thread | None = None + self.updater: Any | None = None # ensure attribute exists + + if not self.use_internal() and sys.platform == 'win32': + self._init_winsparkle() + def shutdown_request(self) -> None: """Receive (Win)Sparkle shutdown request and send it to parent.""" if not config.shutting_down and self.root: @@ -116,61 +141,38 @@ class Updater: :return: bool """ - if self.provider == 'internal': - return True + return self.provider == 'internal' - return False + def _init_winsparkle(self) -> None: + """Initialize WinSparkle updater for Windows.""" + import ctypes + try: + self.updater = cast(ctypes.CDLL, ctypes.cdll.WinSparkle) + self.updater.win_sparkle_set_appcast_url(get_update_feed().encode()) # Set the appcast URL - def __init__(self, tkroot: tk.Tk | None = None, provider: str = 'internal'): - """ - Initialise an Updater instance. + # Set the appversion *without* build metadata, as WinSparkle + # doesn't do proper Semantic Version checks. + # NB: It 'accidentally' supports pre-release due to how it + # splits and compares strings: + # + self.updater.win_sparkle_set_app_build_version(str(appversion_nobuild())) - :param tkroot: reference to the root window of the GUI - :param provider: 'internal' or other string if not - """ - self.root: tk.Tk | None = tkroot - self.provider: str = provider - self.thread: threading.Thread | None = None + # set up shutdown callback + self.callback_t = ctypes.CFUNCTYPE(None) # keep reference + self.callback_fn = self.callback_t(self.shutdown_request) + self.updater.win_sparkle_set_shutdown_request_callback(self.callback_fn) - if self.use_internal(): - return + # Get WinSparkle running + self.updater.win_sparkle_init() - if sys.platform == 'win32': - import ctypes - - try: - self.updater: ctypes.CDLL | None = ctypes.cdll.WinSparkle - - # Set the appcast URL - self.updater.win_sparkle_set_appcast_url(get_update_feed().encode()) - - # Set the appversion *without* build metadata, as WinSparkle - # doesn't do proper Semantic Version checks. - # NB: It 'accidentally' supports pre-release due to how it - # splits and compares strings: - # - self.updater.win_sparkle_set_app_build_version(str(appversion_nobuild())) - - # set up shutdown callback - self.callback_t = ctypes.CFUNCTYPE(None) # keep reference - self.callback_fn = self.callback_t(self.shutdown_request) - self.updater.win_sparkle_set_shutdown_request_callback(self.callback_fn) - - # Get WinSparkle running - self.updater.win_sparkle_init() - - except Exception: - print_exc() - self.updater = None - if not os.getenv("EDMC_NO_UI"): - messagebox.showerror( - title=appname, - message="Updater Failed to Initialize. Please file a bug report!" - ) - else: - logger.error("Updater Failed to Initialize. Please file a bug report!") - - return + except Exception: + print_exc() + self.updater = None + msg = "Updater Failed to Initialize. Please file a bug report!" + if not os.getenv("EDMC_NO_UI"): + messagebox.showerror(title=appname, message=msg) + else: + logger.error(msg) def set_automatic_updates_check(self, onoroff: bool) -> None: """ @@ -187,10 +189,8 @@ class Updater: def check_for_updates(self) -> None: """Trigger the requisite method to check for an update.""" if self.use_internal(): - self.thread = threading.Thread(target=self.worker, name='update worker') - self.thread.daemon = True + self.thread = threading.Thread(target=self.worker, name='update worker', daemon=True) self.thread.start() - elif sys.platform == 'win32' and self.updater: self.updater.win_sparkle_check_update_with_ui() @@ -218,7 +218,6 @@ class Updater: except requests.RequestException as ex: logger.exception(f'Error retrieving update_feed file: {ex}') - return None try: @@ -226,7 +225,6 @@ class Updater: except SyntaxError as ex: logger.exception(f'Syntax error in update_feed file: {ex}') - return None # For *these* purposes all systems are the same as 'windows', as @@ -270,7 +268,6 @@ class Updater: # LANG: Update Available Text status['text'] = tr.tl("{NEWVER} is available").format(NEWVER=newversion.title) self.root.update_idletasks() - else: logger.info("No new version available at this time") From 30da989bc58c724c02f4b388016c46d888ace26d Mon Sep 17 00:00:00 2001 From: David Sangrey Date: Tue, 11 Nov 2025 22:16:57 -0500 Subject: [PATCH 4/6] [Minor] Update LastError to a Dataclass --- plug.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/plug.py b/plug.py index eaf23d0d..1a8779f7 100644 --- a/plug.py +++ b/plug.py @@ -13,6 +13,7 @@ import logging import operator import os import sys +from dataclasses import dataclass, field import tkinter as tk from datetime import datetime, timedelta, timezone from pathlib import Path @@ -33,14 +34,12 @@ PLUGINS_broken = [] # For asynchronous error display +@dataclass class LastError: """Holds the last plugin error.""" - msg: str | None - root: tk.Tk - - def __init__(self) -> None: - self.msg = None + msg: str | None = None + root: tk.Tk | None = field(default=None, repr=False) # not initialized by default, hide in repr last_error = LastError() From b8fa0f841bb7ea459dcb598dc59ce8f310c00d25 Mon Sep 17 00:00:00 2001 From: David Sangrey Date: Tue, 11 Nov 2025 22:31:54 -0500 Subject: [PATCH 5/6] Revert Bad Label Style Change --- myNotebook.py | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/myNotebook.py b/myNotebook.py index b488916a..ac7978a7 100644 --- a/myNotebook.py +++ b/myNotebook.py @@ -51,13 +51,10 @@ class Label(ttk.Label): """Custom ttk.Label class to fix some display issues.""" def __init__(self, master: ttk.Frame | None = None, **kw): - style = ttk.Style() - if sys.platform == 'win32': - custom_style = 'nb.TLabel' # Create or update a style to emulate the tk.Label colors - style.configure(custom_style, foreground=PAGEFG, background=PAGEBG) - else: - custom_style = 'TLabel' # Use the platform default ttk style - kw.setdefault('style', custom_style) + kw['foreground'] = kw.pop('foreground', PAGEFG if sys.platform == 'win32' + else ttk.Style().lookup('TLabel', 'foreground')) + kw['background'] = kw.pop('background', PAGEBG if sys.platform == 'win32' + else ttk.Style().lookup('TLabel', 'background')) super().__init__(master, **kw) From 03cbe8553517ec80e5763097a16aac40a696effc Mon Sep 17 00:00:00 2001 From: David Sangrey Date: Tue, 11 Nov 2025 23:17:02 -0500 Subject: [PATCH 6/6] [2116] A Few More Hand-Overs --- EDMarketConnector.py | 2 +- plugins/edsm.py | 10 +++++----- plugins/inara.py | 4 ++-- plugins/spansh_core.py | 5 +++-- 4 files changed, 11 insertions(+), 10 deletions(-) diff --git a/EDMarketConnector.py b/EDMarketConnector.py index 0bdfb8c9..a59bbebc 100755 --- a/EDMarketConnector.py +++ b/EDMarketConnector.py @@ -2052,7 +2052,7 @@ def show_killswitch_poppup(root=None): idx += 1 idx += 1 - ok_button = tk.Button(frame, text="Ok", command=tl.destroy) + ok_button = ttk.Button(frame, text="Ok", command=tl.destroy) ok_button.grid(columnspan=2, sticky=tk.EW) diff --git a/plugins/edsm.py b/plugins/edsm.py index a2e5004f..e1e6b168 100644 --- a/plugins/edsm.py +++ b/plugins/edsm.py @@ -90,11 +90,11 @@ class This: self.newgame: bool = False # starting up - batch initial burst of events self.newgame_docked: bool = False # starting up while docked self.navbeaconscan: int = 0 # batch up burst of Scan events after NavBeaconScan - self.system_link: tk.Widget | None = None + self.system_link: ttk.Widget | None = None self.system_name: tk.Tk | None = None self.system_address: int | None = None # Frontier SystemAddress self.system_population: int | None = None - self.station_link: tk.Widget | None = None + self.station_link: ttk.Widget | None = None self.station_name: str | None = None self.station_marketid: int | None = None # Frontier MarketID self.on_foot = False @@ -109,7 +109,7 @@ class This: self.log: tk.IntVar | None = None self.log_button: ttk.Checkbutton | None = None - self.label: tk.Widget | None = None + self.label: ttk.Widget | None = None self.cmdr_label: nb.Label | None = None self.cmdr_text: nb.Label | None = None @@ -729,8 +729,8 @@ def send_to_edsm( # noqa: CCR001 # Respect rate limits if they exist if remaining == 0: # Calculate sleep time until the rate limit reset time - reset_time = datetime.utcfromtimestamp(reset) - current_time = datetime.utcnow() + reset_time = datetime.fromtimestamp(reset, tz=timezone.utc) + current_time = datetime.now(timezone.utc) sleep_time = (reset_time - current_time).total_seconds() diff --git a/plugins/inara.py b/plugins/inara.py index e398a3f3..d2fd1efc 100644 --- a/plugins/inara.py +++ b/plugins/inara.py @@ -113,11 +113,11 @@ class This: self.timer_run = True # Main window clicks - self.system_link: tk.Widget = None # type: ignore + self.system_link: ttk.Widget = None # type: ignore self.system_name: str | None = None # type: ignore self.system_address: str | None = None # type: ignore self.system_population: int | None = None - self.station_link: tk.Widget = None # type: ignore + self.station_link: ttk.Widget = None # type: ignore self.station_name = None self.station_marketid = None diff --git a/plugins/spansh_core.py b/plugins/spansh_core.py index 1b7536c5..5a3e541d 100644 --- a/plugins/spansh_core.py +++ b/plugins/spansh_core.py @@ -22,6 +22,7 @@ referenced in this file (or only in any other core plugin), and if so... from __future__ import annotations import tkinter as tk +from tkinter import ttk from typing import Any import requests from companion import CAPIData @@ -39,11 +40,11 @@ class This: def __init__(self): self.parent: tk.Tk self.shutting_down = False # Plugin is shutting down. - self.system_link: tk.Widget = None # type: ignore + self.system_link: ttk.Widget = None # type: ignore self.system_name: str | None = None self.system_address: str | None = None self.system_population: int | None = None - self.station_link: tk.Widget = None # type: ignore + self.station_link: ttk.Widget = None # type: ignore self.station_name = None self.station_marketid = None self.on_foot = False