From 813cf92521045cbe121c5215e4e2d56859738ce5 Mon Sep 17 00:00:00 2001 From: David Sangrey Date: Sat, 23 Mar 2024 16:54:13 -0400 Subject: [PATCH 1/4] [1133] Add ContextMenu Globally --- monitor.py | 2 ++ myNotebook.py | 54 +++++++++++++++++++++++++++++++++++++++++--- requirements-dev.txt | 14 ++++++------ 3 files changed, 60 insertions(+), 10 deletions(-) diff --git a/monitor.py b/monitor.py index 8364f95b..e7f99543 100644 --- a/monitor.py +++ b/monitor.py @@ -63,6 +63,8 @@ elif sys.platform == 'win32': GetWindowText = ctypes.windll.user32.GetWindowTextW GetWindowText.argtypes = [HWND, LPWSTR, ctypes.c_int] GetWindowTextLength = ctypes.windll.user32.GetWindowTextLengthW + GetWindowTextLength.argtypes = [ctypes.wintypes.HWND] + GetWindowTextLength.restype = ctypes.c_int GetProcessHandleFromHwnd = ctypes.windll.oleacc.GetProcessHandleFromHwnd diff --git a/myNotebook.py b/myNotebook.py index 6fa35774..02b1eb45 100644 --- a/myNotebook.py +++ b/myNotebook.py @@ -77,7 +77,7 @@ class Label(tk.Label): """Custom tk.Label class to fix some display issues.""" def __init__(self, master: ttk.Frame | None = None, **kw): - # This format chosen over `sys.platform in (...)` as mypy and friends dont understand that + # This format chosen over `sys.platform in (...)` as mypy and friends don't understand that if sys.platform in ('darwin', 'win32'): kw['foreground'] = kw.pop('foreground', PAGEFG) kw['background'] = kw.pop('background', PAGEBG) @@ -87,7 +87,55 @@ class Label(tk.Label): tk.Label.__init__(self, master, **kw) # Just use tk.Label on all platforms -class Entry(sys.platform == 'darwin' and tk.Entry or ttk.Entry): # type: ignore +class EntryMenu(ttk.Entry): + """Extended entry widget that includes a context menu with Copy, Cut-and-Paste commands.""" + + def __init__(self, *args: ttk.Frame | None, **kwargs) -> None: + super().__init__(*args, **kwargs) + + self.menu = tk.Menu(self, tearoff=False) + self.menu.add_command(label="Copy", command=self.copy) + self.menu.add_command(label="Cut", command=self.cut) + self.menu.add_separator() + self.menu.add_command(label="Paste", command=self.paste) + self.menu.add_separator() + self.menu.add_command(label="Select All", command=self.select_all) + + self.bind("", self.display_popup) + + def display_popup(self, event: tk.Event) -> None: + """Display the menu popup.""" + self.menu.post(event.x_root, event.y_root) + + def select_all(self) -> None: + """Select all the text within the Entry.""" + self.selection_range(0, tk.END) + self.focus_set() + + def copy(self) -> None: + """Copy the selected Entry text.""" + if self.selection_present(): + self.clipboard_clear() + self.clipboard_append(self.selection_get()) + + def cut(self) -> None: + """Cut the selected Entry text.""" + if self.selection_present(): + self.copy() + self.delete(tk.SEL_FIRST, tk.SEL_LAST) + + def paste(self) -> None: + """Paste the selected Entry text.""" + if self.selection_present(): + self.delete(tk.SEL_FIRST, tk.SEL_LAST) + try: + text = self.clipboard_get() + self.insert(tk.INSERT, text) + except tk.TclError: + pass # No text in clipboard or clipboard is not text + + +class Entry(sys.platform == 'darwin' and tk.Entry or EntryMenu or ttk.Entry): # type: ignore """Custom t(t)k.Entry class to fix some display issues.""" def __init__(self, master: ttk.Frame | None = None, **kw): @@ -95,7 +143,7 @@ class Entry(sys.platform == 'darwin' and tk.Entry or ttk.Entry): # type: ignore kw['highlightbackground'] = kw.pop('highlightbackground', PAGEBG) tk.Entry.__init__(self, master, **kw) else: - ttk.Entry.__init__(self, master, **kw) + EntryMenu.__init__(self, master, **kw) class Button(sys.platform == 'darwin' and tk.Button or ttk.Button): # type: ignore diff --git a/requirements-dev.txt b/requirements-dev.txt index 73ab5465..41c3a928 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -5,7 +5,7 @@ wheel # We can't rely on just picking this up from either the base (not venv), # or venv-init-time version. Specify here so that dependabot will prod us # about new versions. -setuptools==69.1.1 +setuptools==69.2.0 # Static analysis tools flake8==7.0.0 @@ -18,14 +18,14 @@ flake8-noqa==1.4.0 flake8-polyfill==1.0.2 flake8-use-fstring==1.4 -mypy==1.8.0 +mypy==1.9.0 pep8-naming==0.13.3 -safety==2.3.5 -types-requests==2.31.0.20240125 +safety==3.0.1 +types-requests==2.31.0.20240311 types-pkg-resources==0.1.3 # Code formatting tools -autopep8==2.0.4 +autopep8==2.1.0 # Git pre-commit checking pre-commit==3.6.2 @@ -38,9 +38,9 @@ grip==4.6.2 py2exe==0.13.0.1; sys_platform == 'win32' # Testing -pytest==8.0.2 +pytest==8.1.1 pytest-cov==4.1.0 # Pytest code coverage support -coverage[toml]==7.4.1 # pytest-cov dep. This is here to ensure that it includes TOML support for pyproject.toml configs +coverage[toml]==7.4.4 # pytest-cov dep. This is here to ensure that it includes TOML support for pyproject.toml configs coverage-conditional-plugin==0.9.0 # For manipulating folder permissions and the like. pywin32==306; sys_platform == 'win32' From ccda74c8f103cff0d63d3d605a0de076f53a77d9 Mon Sep 17 00:00:00 2001 From: David Sangrey Date: Sat, 23 Mar 2024 17:05:14 -0400 Subject: [PATCH 2/4] [Minor] Remove Crappy Type Hint --- myNotebook.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/myNotebook.py b/myNotebook.py index 02b1eb45..63bb7dc8 100644 --- a/myNotebook.py +++ b/myNotebook.py @@ -90,7 +90,7 @@ class Label(tk.Label): class EntryMenu(ttk.Entry): """Extended entry widget that includes a context menu with Copy, Cut-and-Paste commands.""" - def __init__(self, *args: ttk.Frame | None, **kwargs) -> None: + def __init__(self, *args, **kwargs) -> None: super().__init__(*args, **kwargs) self.menu = tk.Menu(self, tearoff=False) From 572f724a71a851b717f1a9938fd21e4fd24682c2 Mon Sep 17 00:00:00 2001 From: David Sangrey Date: Thu, 28 Mar 2024 12:59:22 -0400 Subject: [PATCH 3/4] [1471] Add PIL to Improve Clipboard --- L10n/en.template | 5 ++++- build.py | 1 - myNotebook.py | 22 ++++++++++++++++++---- requirements.txt | 1 + 4 files changed, 23 insertions(+), 6 deletions(-) diff --git a/L10n/en.template b/L10n/en.template index f5acb377..bf8d022e 100644 --- a/L10n/en.template +++ b/L10n/en.template @@ -802,4 +802,7 @@ "Ships" = "Ships"; /* update.py: Update Available Text; In files: update.py:229; */ -"{NEWVER} is available" = "{NEWVER} is available"; \ No newline at end of file +"{NEWVER} is available" = "{NEWVER} is available"; + +/* myNotebook.py: Can't Paste Images or Files in Text; */ +"Cannot paste non-text content." = "Cannot paste non-text content."; diff --git a/build.py b/build.py index 1bc96765..2d4ef790 100644 --- a/build.py +++ b/build.py @@ -133,7 +133,6 @@ def build() -> None: "distutils", "_markerlib", "optparse", - "PIL", "simplejson", "unittest", "doctest", diff --git a/myNotebook.py b/myNotebook.py index 63bb7dc8..398b2136 100644 --- a/myNotebook.py +++ b/myNotebook.py @@ -14,7 +14,12 @@ from __future__ import annotations import sys import tkinter as tk -from tkinter import ttk +from tkinter import ttk, messagebox +from typing import TYPE_CHECKING +from PIL import ImageGrab + +if TYPE_CHECKING: + def _(x: str) -> str: return x # Can't do this with styles on OSX - http://www.tkdocs.com/tutorial/styles.html#whydifficult if sys.platform == 'darwin': @@ -126,13 +131,22 @@ class EntryMenu(ttk.Entry): def paste(self) -> None: """Paste the selected Entry text.""" - if self.selection_present(): - self.delete(tk.SEL_FIRST, tk.SEL_LAST) try: + # Attempt to grab an image from the clipboard (apprently also works for files) + img = ImageGrab.grabclipboard() + if img: + # Hijack existing translation, yes it doesn't exactly match here. + # LANG: Generic error prefix - following text is from Frontier auth service; + messagebox.showwarning(_('Error'), + _('Cannot paste non-text content.')) # LANG: Can't Paste Images or Files in Text + return text = self.clipboard_get() + if self.selection_present() and text: + self.delete(tk.SEL_FIRST, tk.SEL_LAST) self.insert(tk.INSERT, text) except tk.TclError: - pass # No text in clipboard or clipboard is not text + # No text in clipboard or clipboard is not text + pass class Entry(sys.platform == 'darwin' and tk.Entry or EntryMenu or ttk.Entry): # type: ignore diff --git a/requirements.txt b/requirements.txt index 398041a1..e0e6138f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,6 @@ certifi==2023.11.17 requests==2.31.0 +pillow==10.2.0 # requests depends on this now ? charset-normalizer==2.1.1 From 0d9607b4f89ee2d351542fb2d69b156e4bce9b3c Mon Sep 17 00:00:00 2001 From: David Sangrey Date: Sat, 30 Mar 2024 16:02:54 -0400 Subject: [PATCH 4/4] [Minor] Add Missing Future Annotation --- config/linux.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/config/linux.py b/config/linux.py index 73100800..51a40626 100644 --- a/config/linux.py +++ b/config/linux.py @@ -5,6 +5,8 @@ Copyright (c) EDCD, All Rights Reserved Licensed under the GNU General Public License. See LICENSE file. """ +from __future__ import annotations + import os import pathlib import sys