mirror of
https://github.com/storytold/pdfcraft.git
synced 2026-11-02 22:41:47 -06:00
Comments: the composer hides while its comment is scrolled away (#4021)
The floating comment card (new note, text box, edit comment) was an egui Area constrained to the whole window. When the page scrolled its comment under the mode bar, the card was pushed back into the window and sat over the mode bar and toolbar until the whole page left the screen. It now shows only while its anchor is inside the document view, and is kept inside that view. While the comment is out of sight the draft is kept, and the editor takes the focus again when it comes back. Test: tests/comments.rs the_composer_hides_while_its_comment_is_scrolled_away scrolls a sticky note's anchor above the document with its page still on screen; it fails without the change (the card sat at y=43, over the toolbar, with the document starting at y=134) and passes with it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
0dc77fe4ed
commit
d6ba2413ba
@@ -1564,6 +1564,7 @@ pub(crate) fn composer(ctx: &egui::Context, view: &mut DocView, info: &DocInfo,
|
||||
};
|
||||
let cx = PageCx { page, xf: &xf, info, tool: QuickTool::Select, prefs, allowed: true, hidden: false, redact_mark: ([0.89, 0.13, 0.13], 1.0) };
|
||||
let anchor = cx.to_screen(c.at);
|
||||
let viewport = view.viewport_rect();
|
||||
let t = Tokens::get(ctx);
|
||||
let mut post = false;
|
||||
let mut cancel = false;
|
||||
@@ -1576,8 +1577,15 @@ pub(crate) fn composer(ctx: &egui::Context, view: &mut DocView, info: &DocInfo,
|
||||
ComposerKind::Replace => "Replacement text",
|
||||
ComposerKind::Edit(_) => "Edit comment",
|
||||
};
|
||||
// Its comment scrolled out of the document: keep the draft until it is back, rather than
|
||||
// pushing the card into the window over the mode bar and toolbar (#4021).
|
||||
if !viewport.contains(anchor) {
|
||||
c.focus = true;
|
||||
return None;
|
||||
}
|
||||
let pos = pos2(anchor.x + 12.0, anchor.y);
|
||||
egui::Area::new(egui::Id::new(("comment-composer", view.id.0))).order(egui::Order::Foreground).fixed_pos(pos).show(ctx, |ui| {
|
||||
let area = egui::Area::new(egui::Id::new(("comment-composer", view.id.0))).order(egui::Order::Foreground).constrain_to(viewport);
|
||||
area.fixed_pos(pos).show(ctx, |ui| {
|
||||
egui::Frame::popup(ui.style()).inner_margin(egui::Margin::same(12)).corner_radius(CornerRadius::same(8)).show(ui, |ui| {
|
||||
ui.set_width(260.0);
|
||||
ui.horizontal(|ui| {
|
||||
|
||||
@@ -675,6 +675,34 @@ fn sticky_note_composer_posts_and_returns_to_select() {
|
||||
assert_eq!(comments(&h).len(), 1);
|
||||
}
|
||||
|
||||
/// The composer leaves with its comment when the page scrolls it out of the document, and comes
|
||||
/// back with the draft (#4021). It used to be pushed back into the window, over the mode bar and
|
||||
/// the toolbar, while its comment was out of sight.
|
||||
#[test]
|
||||
fn the_composer_hides_while_its_comment_is_scrolled_away() {
|
||||
let mut h = harness(|app| app.set_option("quick", "note").unwrap());
|
||||
click_pt(&mut h, (250.0, 180.0));
|
||||
field(&h, "Add a comment").type_text("Draft");
|
||||
h.run_steps(2);
|
||||
let editors = |h: &Harness<'static, PdfCraftApp>| -> Vec<egui::Rect> {
|
||||
h.query_all_by(|n| n.role() == egui::accesskit::Role::MultilineTextInput).map(|n| n.rect()).collect()
|
||||
};
|
||||
let viewport = h.state().views[0].viewport_rect();
|
||||
assert!(editors(&h).iter().any(|r| viewport.contains(r.center())), "the composer opens in the document");
|
||||
// The page scrolled up: it still shows, the comment near its top doesn't.
|
||||
h.state_mut().views[0].goto = Some((0, 0.4));
|
||||
h.run_steps(4);
|
||||
assert!(h.state().views[0].page_screen_rect(0).is_some_and(|r| r.bottom() > viewport.top()), "page 1 still shows");
|
||||
assert!(at(&h, 250.0, 180.0).y < viewport.top(), "the comment is scrolled away");
|
||||
let shown = editors(&h);
|
||||
assert!(shown.is_empty(), "the composer stays with its comment, not over the toolbar: {shown:?} (document {viewport:?})");
|
||||
// Back again, the draft is still there.
|
||||
h.state_mut().views[0].goto = Some((0, 0.0));
|
||||
h.run_steps(4);
|
||||
assert!(editors(&h).iter().any(|r| viewport.contains(r.center())), "the composer is back");
|
||||
assert_eq!(h.state().views[0].comments.composer.as_ref().map(|c| c.text.as_str()), Some("Draft"));
|
||||
}
|
||||
|
||||
/// The rectangle of the comment whose text starts with `text`.
|
||||
fn rect_of(h: &Harness<'static, PdfCraftApp>, text: &str) -> [f32; 4] {
|
||||
let c = comments(h);
|
||||
|
||||
Reference in New Issue
Block a user