Merge PR #3056: fix(ui): the back arrows leave Edit as the Edit tab does

tests/it/control.rs: kept main's side (the PR's unrelated wait-loop hunk dropped, per the review's fix).
This commit is contained in:
aiongg
2026-10-24 06:59:47 +00:00
4 changed files with 79 additions and 21 deletions
+5 -5
View File
@@ -2302,11 +2302,11 @@ impl PdfCraftApp {
}
/// Changes the workspace and the tool that goes with it. The mode bar (through
/// [`Self::select_mode`]) and the Read mode command both come here, so they leave Edit alike.
/// Edit turns on Edit text & images at once, as Acrobat does: every paragraph and image on the
/// page gets its box and is editable with one click. Leaving Edit puts the editing tools down
/// again and applies a paragraph still open in the editor.
fn enter_mode(&mut self, mode: Mode) {
/// [`Self::select_mode`]), the Read mode command and the tool panels' back arrows all come
/// here, so they leave Edit alike. Edit turns on Edit text & images at once, as Acrobat does:
/// every paragraph and image on the page gets its box and is editable with one click. Leaving
/// Edit puts the editing tools down again and applies a paragraph still open in the editor.
pub(crate) fn enter_mode(&mut self, mode: Mode) {
self.mode = mode;
if mode == Mode::Edit {
self.quick_tool = QuickTool::EditText;
+5 -1
View File
@@ -168,7 +168,6 @@ pub(crate) fn panel(app: &mut PdfCraftApp, ui: &mut egui::Ui, t: &Tokens) {
} else if back {
view.organize = false;
app.left = LeftPanel::AllTools;
app.mode = crate::Mode::AllTools;
}
match act {
Some(Act::Edit(edit)) => view.pending_edit = Some(*edit),
@@ -176,6 +175,11 @@ pub(crate) fn panel(app: &mut PdfCraftApp, ui: &mut egui::Ui, t: &Tokens) {
Some(Act::Command(command)) => app.run_command(command),
None => {}
}
// Leaving the workspace needs the whole app, so it waits until the view is done with: leaving
// Edit puts Edit text down and applies a paragraph still open on the page.
if back && !close {
app.enter_mode(crate::Mode::AllTools);
}
}
/// Whether a row works in this build.
+2 -2
View File
@@ -157,7 +157,7 @@ fn tool_detail(app: &mut PdfCraftApp, ui: &mut egui::Ui, t: &Tokens, g: &'static
let (back, close) = panel_header(ui, t, g.label, Some(tl!("Back to all tools")));
if back {
app.left = LeftPanel::AllTools;
app.mode = crate::Mode::AllTools;
app.enter_mode(crate::Mode::AllTools);
}
if close {
app.left_open = false;
@@ -302,7 +302,7 @@ fn edit_panel(app: &mut PdfCraftApp, ui: &mut egui::Ui, t: &Tokens, g: &'static
ui.horizontal(|ui| {
if from_all_tools && icons::button(ui, "chevron-left", 26.0, false, tl!("Back to all tools")).clicked() {
app.left = LeftPanel::AllTools;
app.mode = crate::Mode::AllTools;
app.enter_mode(crate::Mode::AllTools);
}
// "Edit" under the Edit tab, as Acrobat titles it; the tool's own name from All tools.
let title = if from_all_tools { tl!(g.label) } else { tl!("Edit") };
+67 -13
View File
@@ -3479,17 +3479,19 @@ fn editing_existing_text_in_place() {
assert_eq!(texts_of(s, 0), ["Chapter One"], "the page shows it");
}
/// The Read mode command (View ▸ Read mode, its shortcut, the palette) leaves Edit as the Edit tab
/// does when another tab is chosen (#2241): Edit text & images is put down, and a paragraph still
/// open in the editor is applied instead of staying open, editable, over the page in Read mode.
#[test]
fn the_read_mode_command_applies_an_open_paragraph_and_puts_edit_text_down() {
/// Under the Edit tab, opens the line "Page 1" (at (20, 150) on a 200 × 300 page, 24 pt) in the
/// paragraph editor and retypes it as "Chapter One", leaving the editor open.
fn edit_tab_with_an_open_paragraph(h: &mut Harness<'static, PdfCraftApp>) {
use pdfcraft_ui_egui::{Mode, QuickTool};
let mut h = harness(1, |_| {});
h.get_by_label("Edit").click();
h.run_steps(3);
assert_eq!((h.state().mode, h.state().quick_tool), (Mode::Edit, QuickTool::EditText));
// Open the line "Page 1" (at (20, 150) on a 200 × 300 page, 24 pt) and retype it.
open_the_first_line(h);
}
/// With Edit text & images on, opens the line "Page 1" in the paragraph editor and retypes it as
/// "Chapter One", leaving the editor open.
fn open_the_first_line(h: &mut Harness<'static, PdfCraftApp>) {
let r = h.state().views[0].page_screen_rect(0).expect("on screen");
let at = egui::pos2(r.left() + 40.0 / 200.0 * r.width(), r.top() + (300.0 - 158.0) / 300.0 * r.height());
h.hover_at(at);
@@ -3501,18 +3503,70 @@ fn the_read_mode_command_applies_an_open_paragraph_and_puts_edit_text_down() {
assert_eq!(h.state().views[0].line_editor.as_ref().expect("the line opens for editing").text, "Page 1");
h.state_mut().views[0].line_editor.as_mut().unwrap().text = "Chapter One".into();
h.run_steps(1);
assert!(h.state_mut().execute("view.read_mode"));
h.run_steps(3);
let s = h.state();
assert_eq!(s.mode, Mode::Read);
assert_eq!(s.quick_tool, QuickTool::Select, "Edit text & images is put down");
assert!(s.views[0].line_editor.is_none(), "no paragraph editor is left open in Read mode");
}
/// Edit was left with the paragraph [`edit_tab_with_an_open_paragraph`] opened: Edit text & images
/// is put down, and the paragraph's edit is applied instead of its editor staying open over the page.
fn assert_edit_text_put_down_and_the_paragraph_applied(s: &PdfCraftApp) {
assert_eq!(s.quick_tool, pdfcraft_ui_egui::QuickTool::Select, "Edit text & images is put down");
assert!(s.views[0].line_editor.is_none(), "no paragraph editor is left open");
let doc = s.session.get(s.views[0].id).unwrap();
assert_eq!(doc.can_undo(), Some("Edit text"), "the open paragraph's edit is applied");
assert_eq!(doc.text_lines(0)[0].text, "Chapter One");
assert_eq!(texts_of(s, 0), ["Chapter One"], "the page shows it");
}
/// The Read mode command (View ▸ Read mode, its shortcut, the palette) leaves Edit as the Edit tab
/// does when another tab is chosen (#2241): Edit text & images is put down, and a paragraph still
/// open in the editor is applied instead of staying open, editable, over the page in Read mode.
#[test]
fn the_read_mode_command_applies_an_open_paragraph_and_puts_edit_text_down() {
let mut h = harness(1, |_| {});
edit_tab_with_an_open_paragraph(&mut h);
assert!(h.state_mut().execute("view.read_mode"));
h.run_steps(3);
assert_eq!(h.state().mode, pdfcraft_ui_egui::Mode::Read);
assert_edit_text_put_down_and_the_paragraph_applied(h.state());
}
/// The Edit panel's back arrow (it has one when opened from All tools; the Edit tab is its own way
/// back) leaves for All tools as the mode bar does: Edit text & images is put down and a paragraph
/// still open in the editor is applied, instead of every paragraph keeping its box, and the editor
/// staying open, under All tools.
#[test]
fn the_edit_panel_back_arrow_applies_an_open_paragraph_and_puts_edit_text_down() {
use pdfcraft_ui_egui::{LeftPanel, Mode, QuickTool};
let mut h = harness(1, |_| {});
// All tools ▸ Edit a PDF ▸ Edit text & images: the Edit panel, under All tools.
assert!(h.state_mut().execute("edit.edit_text"));
h.run_steps(3);
assert_eq!((h.state().mode, h.state().quick_tool), (Mode::AllTools, QuickTool::EditText));
open_the_first_line(&mut h);
h.get_by_label("Back to all tools").click();
h.run_steps(3);
assert_eq!((h.state().mode, h.state().left), (Mode::AllTools, LeftPanel::AllTools));
assert_edit_text_put_down_and_the_paragraph_applied(h.state());
}
/// Organize pages, opened under the Edit tab, leaves Edit the same way through its own back arrow.
#[test]
fn the_organize_back_arrow_applies_an_open_paragraph_and_puts_edit_text_down() {
use pdfcraft_ui_egui::{LeftPanel, Mode};
let mut h = harness(1, |_| {});
edit_tab_with_an_open_paragraph(&mut h);
// What the Edit panel's Organize pages row runs.
assert!(h.state_mut().execute("page.organize"));
h.run_steps(3);
assert!(h.state().views[0].organize, "the page grid opens");
assert!(h.state().views[0].line_editor.is_some(), "the paragraph is still open behind the grid");
h.get_by_label("Back to all tools").click();
h.run_steps(3);
let s = h.state();
assert_eq!((s.mode, s.left), (Mode::AllTools, LeftPanel::AllTools));
assert!(!s.views[0].organize, "the grid closes");
assert_edit_text_put_down_and_the_paragraph_applied(s);
}
#[test]
fn text_tool_clicking_source_text_edits_instead_of_adding_a_copy() {
let mut h = harness(1, |_| {});