From c91e04c19fd75ea2b531a8f1924d2aa9fbed929a Mon Sep 17 00:00:00 2001 From: vb Date: Fri, 7 Nov 2025 15:24:14 +0100 Subject: [PATCH] adding copy, paste, and cut functionalities to the clipboard menu --- README.md | 2 +- src/GUI.py | 39 +++++++++++++++++++++++-- src/ImageManipulation/CutToClipboard.py | 34 +++++++++++++++++++++ 3 files changed, 71 insertions(+), 4 deletions(-) create mode 100644 src/ImageManipulation/CutToClipboard.py diff --git a/README.md b/README.md index 1899d7e..bd17b30 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ File menu Clipboard menu - [x] Copy -- [ ] Paste +- [x] Paste - [ ] Cut Image menu diff --git a/src/GUI.py b/src/GUI.py index 0bc652f..030e453 100644 --- a/src/GUI.py +++ b/src/GUI.py @@ -14,6 +14,7 @@ from utils.image_properties import ImagePropertiesHandler from utils.filter_params import FilterParamsHandler from ImageManipulation.CopyToClipboard import CopyToClipboard from ImageManipulation.PasteFromClipboard import PasteFromClipboard +from ImageManipulation.CutToClipboard import CutToClipboard from functools import partial @@ -129,6 +130,7 @@ class GUI: clipboard_menu = tk.Menu(menu, tearoff=0) 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="Cut Image", accelerator="Ctrl+X", command=lambda: self._cutImage()) clipboard_menu.add_command(label="Paste Image", accelerator="Ctrl+V", command=lambda: self._pasteImage()) tools_menu = tk.Menu(menu, tearoff=0) menu.add_cascade(label="Tools", menu=tools_menu) @@ -244,6 +246,7 @@ class GUI: root.bind_all('', lambda event: self._zoomIn()) # Plus key without shift root.bind_all('', lambda event: self._zoomOut()) root.bind_all('', lambda event: self._copyImage()) + root.bind_all('', lambda event: self._cutImage()) root.bind_all('', lambda event: self._pasteImage()) root.mainloop() @@ -265,12 +268,12 @@ class GUI: self._renderCurrentImage() def _renderCurrentImage(self) -> None: - if self._currentImage is None or self._currentImage.getImage() is None: - return - # Clear canvas self._imageCanvas.delete("all") + if self._currentImage is None or self._currentImage.getImage() is None: + return + pil_img = self._currentImage.getImage() width, height = pil_img.size tk_img = ImageTk.PhotoImage(pil_img) @@ -595,6 +598,36 @@ class GUI: # Clean up the attribute 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: """Paste an image from the system clipboard.""" manipulation = PasteFromClipboard() diff --git a/src/ImageManipulation/CutToClipboard.py b/src/ImageManipulation/CutToClipboard.py new file mode 100644 index 0000000..51cee72 --- /dev/null +++ b/src/ImageManipulation/CutToClipboard.py @@ -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." +