adding copy, paste, and cut functionalities to the clipboard menu

This commit is contained in:
vb
2025-11-07 15:24:14 +01:00
parent e6599a1cd7
commit c91e04c19f
3 changed files with 71 additions and 4 deletions

View File

@@ -13,7 +13,7 @@ File menu
Clipboard menu Clipboard menu
- [x] Copy - [x] Copy
- [ ] Paste - [x] Paste
- [ ] Cut - [ ] Cut
Image menu Image menu

View File

@@ -14,6 +14,7 @@ from utils.image_properties import ImagePropertiesHandler
from utils.filter_params import FilterParamsHandler from utils.filter_params import FilterParamsHandler
from ImageManipulation.CopyToClipboard import CopyToClipboard from ImageManipulation.CopyToClipboard import CopyToClipboard
from ImageManipulation.PasteFromClipboard import PasteFromClipboard from ImageManipulation.PasteFromClipboard import PasteFromClipboard
from ImageManipulation.CutToClipboard import CutToClipboard
from functools import partial from functools import partial
@@ -129,6 +130,7 @@ class GUI:
clipboard_menu = tk.Menu(menu, tearoff=0) clipboard_menu = tk.Menu(menu, tearoff=0)
menu.add_cascade(label="Clipboard", menu=clipboard_menu) menu.add_cascade(label="Clipboard", menu=clipboard_menu)
clipboard_menu.add_command(label="Copy Image", accelerator="Ctrl+C", command=lambda: self._copyImage()) clipboard_menu.add_command(label="Copy Image", accelerator="Ctrl+C", command=lambda: self._copyImage())
clipboard_menu.add_command(label="Cut Image", accelerator="Ctrl+X", command=lambda: self._cutImage())
clipboard_menu.add_command(label="Paste Image", accelerator="Ctrl+V", command=lambda: self._pasteImage()) clipboard_menu.add_command(label="Paste Image", accelerator="Ctrl+V", command=lambda: self._pasteImage())
tools_menu = tk.Menu(menu, tearoff=0) tools_menu = tk.Menu(menu, tearoff=0)
menu.add_cascade(label="Tools", menu=tools_menu) menu.add_cascade(label="Tools", menu=tools_menu)
@@ -244,6 +246,7 @@ class GUI:
root.bind_all('<Control-equal>', lambda event: self._zoomIn()) # Plus key without shift root.bind_all('<Control-equal>', lambda event: self._zoomIn()) # Plus key without shift
root.bind_all('<Control-minus>', lambda event: self._zoomOut()) root.bind_all('<Control-minus>', lambda event: self._zoomOut())
root.bind_all('<Control-c>', lambda event: self._copyImage()) root.bind_all('<Control-c>', lambda event: self._copyImage())
root.bind_all('<Control-x>', lambda event: self._cutImage())
root.bind_all('<Control-v>', lambda event: self._pasteImage()) root.bind_all('<Control-v>', lambda event: self._pasteImage())
root.mainloop() root.mainloop()
@@ -265,12 +268,12 @@ class GUI:
self._renderCurrentImage() self._renderCurrentImage()
def _renderCurrentImage(self) -> None: def _renderCurrentImage(self) -> None:
if self._currentImage is None or self._currentImage.getImage() is None:
return
# Clear canvas # Clear canvas
self._imageCanvas.delete("all") self._imageCanvas.delete("all")
if self._currentImage is None or self._currentImage.getImage() is None:
return
pil_img = self._currentImage.getImage() pil_img = self._currentImage.getImage()
width, height = pil_img.size width, height = pil_img.size
tk_img = ImageTk.PhotoImage(pil_img) tk_img = ImageTk.PhotoImage(pil_img)
@@ -595,6 +598,36 @@ class GUI:
# Clean up the attribute # Clean up the attribute
delattr(self._currentImage, '_clipboard_copy_success') delattr(self._currentImage, '_clipboard_copy_success')
def _cutImage(self) -> None:
"""Cut the current image to the system clipboard (copy and remove)."""
if self._currentImage is None or self._currentImage.getImage() is None:
messagebox.showwarning("No Image", "Please load an image first.")
return
manipulation = CutToClipboard()
manipulation.manipulateImage(self._currentImage, {})
# Check if cut was successful
if hasattr(self._currentImage, '_clipboard_cut_success'):
if self._currentImage._clipboard_cut_success:
# Re-render the canvas (will be empty now)
self._renderCurrentImage()
messagebox.showinfo("Cut", "Image cut to clipboard.")
else:
error_msg = getattr(self._currentImage, '_clipboard_cut_error',
"Failed to cut image to clipboard.")
messagebox.showerror(
"Cut Error",
f"{error_msg}\n\n"
"Windows: Please install pywin32 (pip install pywin32)\n"
"Linux: Please install xclip (sudo apt-get install xclip)"
)
# Clean up the attributes
if hasattr(self._currentImage, '_clipboard_cut_success'):
delattr(self._currentImage, '_clipboard_cut_success')
if hasattr(self._currentImage, '_clipboard_cut_error'):
delattr(self._currentImage, '_clipboard_cut_error')
def _pasteImage(self) -> None: def _pasteImage(self) -> None:
"""Paste an image from the system clipboard.""" """Paste an image from the system clipboard."""
manipulation = PasteFromClipboard() manipulation = PasteFromClipboard()

View File

@@ -0,0 +1,34 @@
from .ImageManipulation import ImageManipulation
from ImageContainer import ImageContainer
from typing import Any, List
from utils.clipboard_utils import copy_image_to_clipboard
class CutToClipboard(ImageManipulation):
"""Image manipulation class for cutting images to the system clipboard (copy and remove)."""
def getManipulationName(self) -> str:
return "Cut to Clipboard"
def getParameters(self) -> List[str]:
return []
def manipulateImage(self, image: ImageContainer, parameters: Any) -> None:
if image is None or image.getImage() is None:
image._clipboard_cut_success = False
image._clipboard_cut_error = "No image to cut."
return
pil_img = image.getImage()
# Copy image to clipboard
success = copy_image_to_clipboard(pil_img)
if success:
# Remove the image from the canvas by setting it to None
image._imageData = None
image._clipboard_cut_success = True
else:
# Failed to copy, don't remove the image
image._clipboard_cut_success = False
image._clipboard_cut_error = "Failed to copy image to clipboard."