From f90854520404b4c62b878dc55f1f9a4fb01d9393 Mon Sep 17 00:00:00 2001 From: Vikram Bhaskaran Date: Mon, 12 Oct 2026 23:41:02 +1100 Subject: [PATCH] Paste the picture when the clipboard text beside it is blank. Hosts put whitespace in the text flavour ahead of the bitmap, and that empty text was taken as the paste. --- apps/vectorcraft-web/src/web.rs | 3 ++- crates/ui-egui/src/sysclip.rs | 4 +++- crates/ui-egui/src/tests_sysclip.rs | 5 ++++- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/apps/vectorcraft-web/src/web.rs b/apps/vectorcraft-web/src/web.rs index 6e539a1b..50028187 100644 --- a/apps/vectorcraft-web/src/web.rs +++ b/apps/vectorcraft-web/src/web.rs @@ -205,7 +205,8 @@ fn track_paste(pasted: &Rc>) { let Some(data) = e.clipboard_data() else { return }; let Some(files) = data.files().filter(|f| f.length() > 0) else { return }; // Text is egui's, but for the address a browser's Copy Image puts next to the picture. - if data.get_data("text").is_ok_and(|t| !t.is_empty() && !is_address(&t)) { + // Blank text is not a caption. A picture pasted with it is still the picture. + if data.get_data("text").is_ok_and(|t| !t.trim().is_empty() && !is_address(&t)) { return; } e.prevent_default(); diff --git a/crates/ui-egui/src/sysclip.rs b/crates/ui-egui/src/sysclip.rs index 27a8735d..a2eb8a91 100644 --- a/crates/ui-egui/src/sysclip.rs +++ b/crates/ui-egui/src/sysclip.rs @@ -92,7 +92,9 @@ impl VectorcraftApp { let Some(f) = cb.read(&PASTE_ORDER) else { return Ok(()) }; // Text that only names a picture (its address, or its image markup) goes with a // browser's copied picture: the picture. - let f = if f.mime == TEXT && names_a_picture(&String::from_utf8_lossy(&f.data)) { cb.read(&[BITMAP]).unwrap_or(f) } else { f }; + let text = String::from_utf8_lossy(&f.data); + // Blank text is what some hosts put beside a copied picture. It is not the paste. + let f = if f.mime == TEXT && (text.trim().is_empty() || names_a_picture(&text)) { cb.read(&[BITMAP]).unwrap_or(f) } else { f }; import_command(&f, center) } // Text only: SVG markup is art, other text is left alone. diff --git a/crates/ui-egui/src/tests_sysclip.rs b/crates/ui-egui/src/tests_sysclip.rs index fe053e6b..8ffc8a88 100644 --- a/crates/ui-egui/src/tests_sysclip.rs +++ b/crates/ui-egui/src/tests_sysclip.rs @@ -159,7 +159,10 @@ fn text_from_another_app_pastes_as_point_text_and_svg_text_as_art() { run(&mut app, "edit.paste", json!({})); assert_eq!(pasted(&app).len(), 2); assert!(pasted(&app).iter().all(|n| matches!(n.kind, NodeKind::Path { .. }))); - // Text that can't be pasted pastes nothing (not the stale internal clipboard). + // Blank text beside a picture is the picture. Text alone that can't be pasted adds nothing. + copy_elsewhere(&board, vec![(TEXT, b" \r\n".to_vec()), (PNG, blue_png())]); + run(&mut app, "edit.paste", json!({})); + assert!(matches!(pasted(&app)[0].kind, NodeKind::Image(_)), "blank text yields the picture"); let before = count(&app); copy_elsewhere(&board, vec![(TEXT, b" \r\n".to_vec())]); assert!(app.run("edit.paste", json!({})).is_err());