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'