mirror of
https://github.com/EDCD/EDMarketConnector.git
synced 2025-04-13 07:47:14 +03:00
Merge pull request #2183 from HullSeals/enhancement/1133/context-menu-Entry
[1133] Add ContextMenu Globally
This commit is contained in:
commit
29c43cbc51
@ -802,4 +802,7 @@
|
|||||||
"Ships" = "Ships";
|
"Ships" = "Ships";
|
||||||
|
|
||||||
/* update.py: Update Available Text; In files: update.py:229; */
|
/* 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
build.py
1
build.py
@ -133,7 +133,6 @@ def build() -> None:
|
|||||||
"distutils",
|
"distutils",
|
||||||
"_markerlib",
|
"_markerlib",
|
||||||
"optparse",
|
"optparse",
|
||||||
"PIL",
|
|
||||||
"simplejson",
|
"simplejson",
|
||||||
"unittest",
|
"unittest",
|
||||||
"doctest",
|
"doctest",
|
||||||
|
@ -5,6 +5,8 @@ Copyright (c) EDCD, All Rights Reserved
|
|||||||
Licensed under the GNU General Public License.
|
Licensed under the GNU General Public License.
|
||||||
See LICENSE file.
|
See LICENSE file.
|
||||||
"""
|
"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import pathlib
|
import pathlib
|
||||||
import sys
|
import sys
|
||||||
|
@ -63,6 +63,8 @@ elif sys.platform == 'win32':
|
|||||||
GetWindowText = ctypes.windll.user32.GetWindowTextW
|
GetWindowText = ctypes.windll.user32.GetWindowTextW
|
||||||
GetWindowText.argtypes = [HWND, LPWSTR, ctypes.c_int]
|
GetWindowText.argtypes = [HWND, LPWSTR, ctypes.c_int]
|
||||||
GetWindowTextLength = ctypes.windll.user32.GetWindowTextLengthW
|
GetWindowTextLength = ctypes.windll.user32.GetWindowTextLengthW
|
||||||
|
GetWindowTextLength.argtypes = [ctypes.wintypes.HWND]
|
||||||
|
GetWindowTextLength.restype = ctypes.c_int
|
||||||
|
|
||||||
GetProcessHandleFromHwnd = ctypes.windll.oleacc.GetProcessHandleFromHwnd
|
GetProcessHandleFromHwnd = ctypes.windll.oleacc.GetProcessHandleFromHwnd
|
||||||
|
|
||||||
|
@ -14,7 +14,12 @@ from __future__ import annotations
|
|||||||
|
|
||||||
import sys
|
import sys
|
||||||
import tkinter as tk
|
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
|
# Can't do this with styles on OSX - http://www.tkdocs.com/tutorial/styles.html#whydifficult
|
||||||
if sys.platform == 'darwin':
|
if sys.platform == 'darwin':
|
||||||
@ -77,7 +82,7 @@ class Label(tk.Label):
|
|||||||
"""Custom tk.Label class to fix some display issues."""
|
"""Custom tk.Label class to fix some display issues."""
|
||||||
|
|
||||||
def __init__(self, master: ttk.Frame | None = None, **kw):
|
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'):
|
if sys.platform in ('darwin', 'win32'):
|
||||||
kw['foreground'] = kw.pop('foreground', PAGEFG)
|
kw['foreground'] = kw.pop('foreground', PAGEFG)
|
||||||
kw['background'] = kw.pop('background', PAGEBG)
|
kw['background'] = kw.pop('background', PAGEBG)
|
||||||
@ -87,7 +92,64 @@ class Label(tk.Label):
|
|||||||
tk.Label.__init__(self, master, **kw) # Just use tk.Label on all platforms
|
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."""
|
"""Custom t(t)k.Entry class to fix some display issues."""
|
||||||
|
|
||||||
def __init__(self, master: ttk.Frame | None = None, **kw):
|
def __init__(self, master: ttk.Frame | None = None, **kw):
|
||||||
@ -95,7 +157,7 @@ class Entry(sys.platform == 'darwin' and tk.Entry or ttk.Entry): # type: ignore
|
|||||||
kw['highlightbackground'] = kw.pop('highlightbackground', PAGEBG)
|
kw['highlightbackground'] = kw.pop('highlightbackground', PAGEBG)
|
||||||
tk.Entry.__init__(self, master, **kw)
|
tk.Entry.__init__(self, master, **kw)
|
||||||
else:
|
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
|
class Button(sys.platform == 'darwin' and tk.Button or ttk.Button): # type: ignore
|
||||||
|
@ -5,7 +5,7 @@ wheel
|
|||||||
# We can't rely on just picking this up from either the base (not venv),
|
# 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
|
# or venv-init-time version. Specify here so that dependabot will prod us
|
||||||
# about new versions.
|
# about new versions.
|
||||||
setuptools==69.1.1
|
setuptools==69.2.0
|
||||||
|
|
||||||
# Static analysis tools
|
# Static analysis tools
|
||||||
flake8==7.0.0
|
flake8==7.0.0
|
||||||
@ -20,8 +20,8 @@ flake8-use-fstring==1.4
|
|||||||
|
|
||||||
mypy==1.9.0
|
mypy==1.9.0
|
||||||
pep8-naming==0.13.3
|
pep8-naming==0.13.3
|
||||||
safety==2.3.5
|
safety==3.0.1
|
||||||
types-requests==2.31.0.20240125
|
types-requests==2.31.0.20240311
|
||||||
types-pkg-resources==0.1.3
|
types-pkg-resources==0.1.3
|
||||||
|
|
||||||
# Code formatting tools
|
# Code formatting tools
|
||||||
@ -38,9 +38,9 @@ grip==4.6.2
|
|||||||
py2exe==0.13.0.1; sys_platform == 'win32'
|
py2exe==0.13.0.1; sys_platform == 'win32'
|
||||||
|
|
||||||
# Testing
|
# Testing
|
||||||
pytest==8.0.2
|
pytest==8.1.1
|
||||||
pytest-cov==4.1.0 # Pytest code coverage support
|
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
|
coverage-conditional-plugin==0.9.0
|
||||||
# For manipulating folder permissions and the like.
|
# For manipulating folder permissions and the like.
|
||||||
pywin32==306; sys_platform == 'win32'
|
pywin32==306; sys_platform == 'win32'
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
certifi==2024.2.2
|
certifi==2024.2.2
|
||||||
requests==2.31.0
|
requests==2.31.0
|
||||||
|
pillow==10.2.0
|
||||||
# requests depends on this now ?
|
# requests depends on this now ?
|
||||||
charset-normalizer==2.1.1
|
charset-normalizer==2.1.1
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user