From ee780df46e89552ed792f0938d772bbc327f1c7b Mon Sep 17 00:00:00 2001 From: Guillem Hermida Date: Sat, 17 Oct 2026 15:45:38 +0200 Subject: [PATCH] fix(ui): the back arrows leave Edit as the Edit tab does The tool panel's back arrow (Back to all tools, in the Edit panel among others) and Organize pages' back arrow set the workspace to All tools directly. Pressed from the Edit tab, they left Edit text & images on under All tools, every paragraph still boxed, and a paragraph open in the editor still open over the page with its edit not applied. Both arrows now go through enter_mode, as the mode bar and the Read mode command do (#3014). Organize calls it once the panel's action has been handed to the view, since the view borrows the app until then. Test: editing.rs::the_edit_panel_back_arrow_applies_an_open_paragraph_and_puts_edit_text_down Test: editing.rs::the_organize_back_arrow_applies_an_open_paragraph_and_puts_edit_text_down --- crates/ui-egui/src/lib.rs | 10 ++-- crates/ui-egui/src/organize_panel.rs | 6 ++- crates/ui-egui/src/panels.rs | 2 +- crates/ui-egui/tests/editing.rs | 69 ++++++++++++++++++++++------ 4 files changed, 67 insertions(+), 20 deletions(-) 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, |_| {});