mirror of
https://github.com/storytold/pdfcraft.git
synced 2026-10-27 11:37:59 -06:00
fix(edit): a refused delete keeps the object selection
Review on #4111: Delete cleared the selection before the edit ran, so a delete the engine refuses (text used as a clipping path) left the document as it was but dropped what the user had selected. The selection now stays until the edit applies; `ObjectSelection::prepare` already clears it when the document changes and keeps it when an edit is refused. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
7d6af8a508
commit
caf189522f
@@ -396,8 +396,9 @@ pub(crate) fn delete_keys(ctx: &egui::Context, view: &mut DocView) {
|
||||
if !ctx.input_mut(|i| i.consume_key(Modifiers::NONE, Key::Delete) || i.consume_key(Modifiers::NONE, Key::Backspace)) {
|
||||
return;
|
||||
}
|
||||
// The selection stays until the edit applies: `prepare` clears it when the document changes,
|
||||
// and a refused delete (text used as a clipping path) leaves it selected.
|
||||
view.pending_edit = delete_edit(page, view.objects.selected.iter().map(|o| o.target).collect());
|
||||
view.objects.clear();
|
||||
}
|
||||
|
||||
/// The edit that deletes `targets` (indexes into one inventory of `page`) as one undo step.
|
||||
|
||||
@@ -4219,6 +4219,30 @@ fn an_ordinary_paragraph_drag_refusal_never_rewrites_the_text() {
|
||||
assert!(h.state().toast.as_ref().unwrap().0.contains("Text used as a clipping path cannot be moved with this selection."));
|
||||
}
|
||||
|
||||
/// A delete the engine refuses (text used as a clipping path) leaves the document as it was and
|
||||
/// keeps the selection, so the user can still move or nudge what they had selected.
|
||||
#[test]
|
||||
fn a_refused_delete_keeps_the_object_selection() {
|
||||
let content = "q BT 4 Tr /F1 12 Tf 60 320 Td (Clipping text) Tj ET Q";
|
||||
let mut h = paragraph_drag_harness(paragraph_drag_fixture(content, 0, 1), 0);
|
||||
let id = h.state().views[0].id;
|
||||
let (generation, bytes) = {
|
||||
let doc = h.state().session.get(id).unwrap();
|
||||
(doc.edit_generation(), doc.bytes.clone())
|
||||
};
|
||||
// An area selection from empty page space around the paragraph.
|
||||
let (center, _) = paragraph_drag_points(&h, "Clipping text", [0.0, 0.0]);
|
||||
drag(&mut h, center - egui::vec2(60.0, 25.0), center + egui::vec2(60.0, 25.0));
|
||||
h.get_by_label("1 object selected");
|
||||
h.key_press(Key::Delete);
|
||||
h.run_steps(4);
|
||||
let doc = h.state().session.get(id).unwrap();
|
||||
assert_eq!((doc.edit_generation(), &doc.bytes), (generation, &bytes), "the refused delete changed nothing");
|
||||
assert!(doc.can_undo().is_none());
|
||||
assert!(h.state().toast.is_some(), "the refusal is reported");
|
||||
h.get_by_label("1 object selected");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn an_ordinary_paragraph_drag_cannot_reuse_an_index_after_an_edit() {
|
||||
let content = "BT /F1 12 Tf 60 120 Td (Discard) Tj ET BT /F1 12 Tf 60 320 Td (Moving alpha) Tj ET BT /F1 12 Tf 60 220 Td (Keep here) Tj ET";
|
||||
@@ -6002,6 +6026,7 @@ fn a_paragraph_selected_by_its_frame_deletes_with_one_key() {
|
||||
press(&mut h, Modifiers::NONE, key);
|
||||
assert!(blocks(&h).is_empty(), "{key:?} deletes the whole paragraph: {:?}", blocks(&h));
|
||||
assert!(h.state().views[0].line_editor.is_none(), "no empty editor is left behind");
|
||||
assert!(h.query_all_by_label_contains("object selected").next().is_none(), "the deleted paragraph is no longer selected");
|
||||
assert_eq!(h.state().session.get(id).unwrap().text_blocks(1)[0].text, "Page 2", "the next page keeps its text");
|
||||
assert_eq!(h.state().session.get(id).unwrap().info.pages.len(), 2, "Delete removed the paragraph, not a page");
|
||||
assert!(h.state_mut().execute("edit.undo"));
|
||||
|
||||
Reference in New Issue
Block a user