From 257fd53bbcf33c8d8d80f2f6f3af16f3739bf430 Mon Sep 17 00:00:00 2001 From: lashman Date: Fri, 6 Mar 2026 13:46:20 +0200 Subject: [PATCH] Add Ctrl+V clipboard paste for images Reads image textures from the system clipboard, saves as temporary PNG files, and adds them to the batch. Shows toast notification on success or when no image is found. --- pixstrip-gtk/src/app.rs | 54 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/pixstrip-gtk/src/app.rs b/pixstrip-gtk/src/app.rs index 31823c1..fd8f2e3 100644 --- a/pixstrip-gtk/src/app.rs +++ b/pixstrip-gtk/src/app.rs @@ -131,6 +131,7 @@ fn setup_shortcuts(app: &adw::Application) { app.set_accels_for_action("win.select-all-images", &["a"]); app.set_accels_for_action("win.deselect-all-images", &["a"]); app.set_accels_for_action("win.undo-last-batch", &["z"]); + app.set_accels_for_action("win.paste-images", &["v"]); app.set_accels_for_action("app.quit", &["q"]); app.set_accels_for_action("win.show-settings", &["comma"]); app.set_accels_for_action("win.show-shortcuts", &["question", "F1"]); @@ -576,6 +577,17 @@ fn setup_window_actions(window: &adw::ApplicationWindow, ui: &WizardUi) { action_group.add_action(&action); } + // Paste images from clipboard (Ctrl+V) + { + let window = window.clone(); + let ui = ui.clone(); + let action = gtk::gio::SimpleAction::new("paste-images", None); + action.connect_activate(move |_, _| { + paste_images_from_clipboard(&window, &ui); + }); + action_group.add_action(&action); + } + // Connect button clicks ui.back_button.connect_clicked({ let action_group = action_group.clone(); @@ -1507,6 +1519,47 @@ fn undo_last_batch(ui: &WizardUi) { ui.toast_overlay.add_toast(toast); } +fn paste_images_from_clipboard(window: &adw::ApplicationWindow, ui: &WizardUi) { + let clipboard = window.clipboard(); + let ui = ui.clone(); + + // Try to read a texture (image) from clipboard + clipboard.read_texture_async(gtk::gio::Cancellable::NONE, move |result| { + if let Ok(Some(texture)) = result { + // Save the texture to a temp file + let temp_dir = std::env::temp_dir().join("pixstrip-clipboard"); + if std::fs::create_dir_all(&temp_dir).is_err() { + ui.toast_overlay.add_toast(adw::Toast::new("Failed to create temporary directory")); + return; + } + let timestamp = std::time::SystemTime::now() + .duration_since(std::time::UNIX_EPOCH) + .unwrap_or_default() + .as_millis(); + let temp_path = temp_dir.join(format!("clipboard-{}.png", timestamp)); + + let bytes = texture.save_to_png_bytes(); + if std::fs::write(&temp_path, bytes.as_ref()).is_ok() { + let mut files = ui.state.loaded_files.borrow_mut(); + if !files.contains(&temp_path) { + files.push(temp_path); + } + let count = files.len(); + drop(files); + update_images_count_label(&ui, count); + + let toast = adw::Toast::new("Pasted image from clipboard"); + toast.set_timeout(2); + ui.toast_overlay.add_toast(toast); + } else { + ui.toast_overlay.add_toast(adw::Toast::new("Failed to save clipboard image")); + } + } else { + ui.toast_overlay.add_toast(adw::Toast::new("No image found in clipboard")); + } + }); +} + fn reset_wizard(ui: &WizardUi) { // Reset state { @@ -2071,6 +2124,7 @@ fn show_shortcuts_window(window: &adw::ApplicationWindow) { ]), ("File Management", &[ ("Ctrl + O", "Add files"), + ("Ctrl + V", "Paste image from clipboard"), ("Ctrl + A", "Select all images"), ("Ctrl + Shift + A", "Deselect all images"), ("Delete", "Remove selected images"),