diff --git a/crates/ui-egui/tests/it/editing.rs b/crates/ui-egui/tests/it/editing.rs index 54c5397840..d71e3bfa85 100644 --- a/crates/ui-egui/tests/it/editing.rs +++ b/crates/ui-egui/tests/it/editing.rs @@ -7499,6 +7499,61 @@ fn add_text_moves_no_paragraph_while_it_holds_a_draft_it_cant_draw() { assert_eq!(h.state().session.get(id).unwrap().text_blocks(0)[0].rect, block.rect, "the paragraph stays"); } +/// With Edit text, a right-click on a comment over a picture opens the comment's menu, and the +/// picture is not selected for its own. +#[test] +fn a_right_click_on_a_comment_over_a_picture_opens_its_menu() { + let mut h = picture_pages(false); + h.state_mut().views[0].image_selection = None; + let shape = pdfcraft_engine::Shape::Rectangle { rect: [60.0, 190.0, 150.0, 230.0] }; + assert!(h.state_mut().apply_edit(pdfcraft_engine::Edit::AddAnnotation(pdfcraft_engine::NewAnnotation { + page: 0, + style: pdfcraft_engine::Style::default_for(&shape), + shape, + contents: "Reviewed".into(), + author: "Tester".into(), + }))); + h.state_mut().views[0].comments.selected = None; + h.run_steps(3); + let on_it = page_at(&h, 0, 100.0, 210.0); + right_click_at(&mut h, on_it); + assert!(h.state().views[0].comments.selected.is_some(), "the comment is selected"); + assert!(h.state().views[0].image_selection.is_none(), "the picture is not"); + assert!(h.query_by_label("Properties…").is_some(), "the comment's menu opens"); +} + +/// In crop mode, a right-click on the next page goes to what lies there, though a clipped artwork's +/// whole frame reaches over it: crop mode ends and the page's menu opens. +#[test] +fn a_right_click_on_the_next_page_leaves_crop_mode() { + let mut h = picture_pages(true); + let on_two = page_at(&h, 1, 100.0, 40.0); + right_click_at(&mut h, on_two); + assert!(h.state().views[0].image_selection.is_none(), "crop mode ends"); + assert!(h.query_by_label("Marquee Zoom").is_some(), "the page's menu opens"); +} + +/// A crop grip takes a press as far off as its cursor shows: 9 px from the grip, outside the box. +#[test] +fn a_crop_grip_takes_a_press_within_its_reach() { + let mut h = picture_pages(true); + let keep = |h: &Harness<'static, PdfCraftApp>| h.state().views[0].image_selection.as_ref().and_then(|s| s.crop.as_ref()).map(|c| c.keep); + let before = keep(&h); + // The box kept is the picture's frame shown, x 30..160, y 170..250: its upper left corner. + let press = page_at(&h, 0, 30.0, 250.0) - egui::vec2(9.0, 0.0); + h.hover_at(press); + h.run_steps(1); + h.drag_at(press); + h.run_steps(1); + for k in 1..=4 { + h.hover_at(press + egui::vec2(8.0 * k as f32, 8.0 * k as f32)); + h.run_steps(1); + } + h.drop_at(press + egui::vec2(32.0, 32.0)); + h.run_steps(2); + assert_ne!(keep(&h), before, "the grip takes the drag"); +} + /// In the page grid, Delete deletes the page chosen there. The picture selected before the grid /// opened is not on screen, and stays. #[test] diff --git a/crates/ui-egui/tests/it/object_selection.rs b/crates/ui-egui/tests/it/object_selection.rs index e5a588aaef..e19f939e2e 100644 --- a/crates/ui-egui/tests/it/object_selection.rs +++ b/crates/ui-egui/tests/it/object_selection.rs @@ -451,3 +451,15 @@ fn a_double_click_on_a_grouped_object_reaches_it() { h.run_steps(2); assert!(h.state().views[0].content.draft.as_ref().is_some_and(|d| d.index == Some(0)), "the added note opens for typing"); } + +/// A double-click on a paragraph selected with others opens it for typing (the user's ruling). +#[test] +fn a_double_click_on_a_grouped_paragraph_opens_it() { + let mut h = harness(); + marquee(&mut h); + // "Group headline" is at x 40, its baseline y 430 of 500. + let headline = at(&h, 80.0, 65.0); + crate::support::input::double_click(&mut h, headline); + h.run_steps(2); + assert!(h.state().views[0].line_editor.is_some(), "the paragraph is open for typing"); +} diff --git a/crates/ui-egui/tests/it/pointer.rs b/crates/ui-egui/tests/it/pointer.rs index 0012d30d61..0a7dc80c63 100644 --- a/crates/ui-egui/tests/it/pointer.rs +++ b/crates/ui-egui/tests/it/pointer.rs @@ -1607,6 +1607,7 @@ fn a_right_click_with_edit_text_on_a_paragraph_under_a_comment_selects_the_comme wait_for_cursor(&mut h, on_text, |c| c != egui::CursorIcon::Default); right_click(&mut h, on_text); assert_eq!(h.state().views[0].comments.selected, Some((0, 0)), "the comment over the paragraph is selected"); + assert!(h.query_by_label("Properties…").is_some(), "its menu opens"); assert_eq!(h.state().views[0].comments.context_at.map(|(page, _)| page), Some(0), "the menu is anchored on the page"); // The rectangle ends at x 200; the line goes on. let beside = at(&h, 230.0, 303.0); @@ -1893,6 +1894,46 @@ fn with_prepare_a_click_that_began_off_the_page_keeps_the_selected_field() { assert!(h.state().views[0].prepare.selected.is_some(), "a click that began off the page leaves it selected"); } +/// With Prepare open, a drag from a highlight draws the selection rectangle: a highlight lets a drag +/// go, so nobody holds it and it is Prepare's. +#[test] +fn with_prepare_a_drag_from_a_highlight_draws_the_selection_rectangle() { + let mut h = open(highlighted_checkbox_pdf(), "150", false); + assert!(h.state_mut().execute("form.prepare")); + h.run_steps(4); + // On the highlight, beside the box; the drag ends past the box's other corner. + let (from, to) = (at(&h, 97.0, 197.0), at(&h, 130.0, 230.0)); + mouse_drag(&mut h, from, to - from); + assert!(h.state().views[0].prepare.selected.is_some(), "the rectangle selects the field inside it"); +} + +/// A right-click while the primary button is held opens the menu of the comment it went to, when that +/// is the one selected, and leaves the selection as it is. +#[test] +fn a_right_click_with_the_button_held_opens_the_selected_comments_menu() { + let mut h = open(comment_on_text_pdf(), "150", false); + // On the rectangle's left edge: an unfilled one takes a press on its border. + let edge = at(&h, 30.0, 303.0); + wait_for_cursor(&mut h, edge, |c| c != egui::CursorIcon::Default); + mouse_click(&mut h, edge); + assert_eq!(h.state().views[0].comments.selected, Some((0, 0)), "the comment is selected"); + h.hover_at(edge); + h.run_steps(1); + h.drag_at(edge); + h.run_steps(1); + let moved = edge + egui::vec2(20.0, 0.0); + h.hover_at(moved); + h.run_steps(1); + for pressed in [true, false] { + h.event(egui::Event::PointerButton { pos: moved, button: egui::PointerButton::Secondary, pressed, modifiers: egui::Modifiers::NONE }); + } + h.run_steps(3); + assert!(h.query_by_label("Properties…").is_some(), "the comment's menu"); + assert_eq!(h.state().views[0].comments.selected, Some((0, 0)), "the selection stays"); + h.drop_at(moved); + h.run_steps(2); +} + /// With Prepare open on a document that can't be changed, a right-click on a field selects nothing /// and opens the page's menu, whose field entries would only be refused. #[test]