diff --git a/crates/ui-egui/src/lib.rs b/crates/ui-egui/src/lib.rs index 27db0e98c..1c10a0a83 100644 --- a/crates/ui-egui/src/lib.rs +++ b/crates/ui-egui/src/lib.rs @@ -2149,11 +2149,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; diff --git a/crates/ui-egui/src/organize_panel.rs b/crates/ui-egui/src/organize_panel.rs index a4c2e8cf7..858e4b8c1 100644 --- a/crates/ui-egui/src/organize_panel.rs +++ b/crates/ui-egui/src/organize_panel.rs @@ -166,7 +166,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), @@ -174,6 +173,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. diff --git a/crates/ui-egui/src/panels.rs b/crates/ui-egui/src/panels.rs index d69148807..38d5dcd37 100644 --- a/crates/ui-egui/src/panels.rs +++ b/crates/ui-egui/src/panels.rs @@ -147,7 +147,7 @@ fn tool_detail(app: &mut PdfCraftApp, ui: &mut egui::Ui, t: &Tokens, g: &'static let (back, close) = panel_header(ui, t, g.label, true); if back { app.left = LeftPanel::AllTools; - app.mode = crate::Mode::AllTools; + app.enter_mode(crate::Mode::AllTools); } if close { app.left_open = false; diff --git a/crates/ui-egui/tests/editing.rs b/crates/ui-egui/tests/editing.rs index fb0e75028..46bfc24f4 100644 --- a/crates/ui-egui/tests/editing.rs +++ b/crates/ui-egui/tests/editing.rs @@ -2629,17 +2629,13 @@ 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. 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); @@ -2651,18 +2647,65 @@ 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 leaves Edit 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}; + let mut h = harness(1, |_| {}); + edit_tab_with_an_open_paragraph(&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, |_| {});