fix(select): a picked picture that is edited away no longer leaves its highlight behind

With the Select tool a click picks a picture and draws a blue highlight over it. The pick was
only cleared by Escape, a drag or another click. Picking a picture, then entering Edit text &
images and deleting it left the highlight on the empty spot, with nothing left to click to
remove it.

The pick now remembers the document's edit generation and is dropped once the document has been
edited since (a delete, a move, Undo), the same condition under which the copy shortcut already
refused it as stale.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
hade0ntema
2026-10-16 10:33:24 +02:00
co-authored by Claude Sonnet 5.5
parent f0c9901c39
commit da48b84b8c
3 changed files with 44 additions and 2 deletions
+1
View File
@@ -3275,6 +3275,7 @@ pub fn document_area(app: &mut PdfCraftApp, index: usize, ui: &mut egui::Ui) {
if tool == QuickTool::Select && !consumed {
crate::image_pick::page_input(&resp, &xf, i, info, doc, pointer, view);
}
crate::image_pick::drop_stale(doc, view);
crate::image_pick::paint(painter, &xf, i, info, view);
comments::page_after_text(&resp, &pcx, view);
if tool == QuickTool::Redact && can_modify {
+14 -2
View File
@@ -9,12 +9,14 @@ use crate::PdfCraftApp;
use crate::canvas::{DocView, PageXform};
use pdfcraft_render::DocInfo;
/// The selected picture: page, index in `page_images` and its box in user space.
/// The selected picture: page, index in `page_images` and its box in user space, and the
/// document's edit generation when it was picked (any later edit may have removed or renumbered it).
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct PickedImage {
pub page: usize,
pub index: usize,
pub rect: [f64; 4],
pub generation: u64,
}
const BLUE: Color32 = Color32::from_rgb(0x3A, 0x7B, 0xF0);
@@ -43,8 +45,18 @@ pub(crate) fn page_input(
let (vx, vy) = xf.screen_to_view(p);
let u = info_page.view_to_user(vx, vy);
let at = [f64::from(u[0]), f64::from(u[1])];
let generation = doc.edit_generation();
view.picked_image =
doc.page_image_at(page, at).and_then(|index| doc.page_images(page).get(index).map(|i| PickedImage { page, index, rect: i.rect }));
doc.page_image_at(page, at).and_then(|index| doc.page_images(page).get(index).map(|i| PickedImage { page, index, rect: i.rect, generation }));
}
/// Forget the selected picture once the document has been edited since it was picked: Edit text &
/// images (or Undo) may have deleted or moved it, and its highlight would stay behind on an empty
/// spot of the page.
pub(crate) fn drop_stale(doc: &pdfcraft_engine::Document, view: &mut DocView) {
if view.picked_image.is_some_and(|p| p.generation != doc.edit_generation()) {
view.picked_image = None;
}
}
/// The selected picture's highlight on page `page`.
+29
View File
@@ -1384,6 +1384,35 @@ fn a_clicked_picture_is_selected_and_copied_in_its_original_format() {
assert_eq!(h.state().views[i].picked_image, None);
}
/// A picture picked with the Select tool, then deleted in Edit text & images, leaves no highlight
/// behind on the empty spot where it was.
#[test]
fn a_picked_picture_that_is_deleted_in_edit_mode_loses_its_highlight() {
let (_, mut h) = picture_harness();
let i = h.state().active.unwrap();
let id = h.state().views[i].id;
let at = h.state().views[i].page_screen_rect(0).expect("on screen").center();
h.hover_at(at);
h.run_steps(1);
h.event(egui::Event::PointerButton { pos: at, button: egui::PointerButton::Primary, pressed: true, modifiers: Default::default() });
h.event(egui::Event::PointerButton { pos: at, button: egui::PointerButton::Primary, pressed: false, modifiers: Default::default() });
h.run_steps(2);
assert!(h.state().views[i].picked_image.is_some(), "picked with the Select tool");
// Edit text & images: click the picture, delete it with the Delete key.
assert!(h.state_mut().execute("edit.edit_text"));
h.run_steps(2);
h.hover_at(at);
h.run_steps(1);
h.drag_at(at);
h.run_steps(1);
h.drop_at(at);
h.run_steps(2);
h.key_press(egui::Key::Delete);
h.run_steps(4);
assert!(h.state().session.get(id).unwrap().page_images(0).is_empty(), "the picture is gone");
assert_eq!(h.state().views[i].picked_image, None, "and so is its highlight");
}
#[test]
fn right_click_on_a_picture_copies_it_at_full_size() {
let (px, mut h) = picture_harness();