Skip to content

Commit

Permalink
Merge pull request #2183 from HullSeals/enhancement/1133/context-menu…
Browse files Browse the repository at this point in the history
…-Entry

[1133] Add ContextMenu Globally
  • Loading branch information
Rixxan authored Apr 5, 2024
2 parents 47d2cf9 + 0d9607b commit 29c43cb
Show file tree
Hide file tree
Showing 7 changed files with 80 additions and 11 deletions.
5 changes: 4 additions & 1 deletion L10n/en.template
Original file line number Diff line number Diff line change
Expand Up @@ -802,4 +802,7 @@
"Ships" = "Ships";

/* update.py: Update Available Text; In files: update.py:229; */
"{NEWVER} is available" = "{NEWVER} is available";
"{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.";
1 change: 0 additions & 1 deletion build.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,6 @@ def build() -> None:
"distutils",
"_markerlib",
"optparse",
"PIL",
"simplejson",
"unittest",
"doctest",
Expand Down
2 changes: 2 additions & 0 deletions config/linux.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
Licensed under the GNU General Public License.
See LICENSE file.
"""
from __future__ import annotations

import os
import pathlib
import sys
Expand Down
2 changes: 2 additions & 0 deletions monitor.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ def _(x: str) -> str:
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

Expand Down
70 changes: 66 additions & 4 deletions myNotebook.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,12 @@

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':
Expand Down Expand Up @@ -77,7 +82,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)
Expand All @@ -87,15 +92,72 @@ def __init__(self, master: ttk.Frame | None = None, **kw):
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, **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("<Button-3>", 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."""
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:
# 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
"""Custom t(t)k.Entry class to fix some display issues."""

def __init__(self, master: ttk.Frame | None = None, **kw):
if sys.platform == 'darwin':
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
Expand Down
10 changes: 5 additions & 5 deletions requirements-dev.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -20,8 +20,8 @@ flake8-use-fstring==1.4

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
Expand All @@ -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'
Expand Down
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
certifi==2024.2.2
requests==2.31.0
pillow==10.2.0
# requests depends on this now ?
charset-normalizer==2.1.1

Expand Down

0 comments on commit 29c43cb

Please sign in to comment.