From 3261b6ddb821373d227fdd19a5f38b811847e286 Mon Sep 17 00:00:00 2001 From: Christoph Ortenburg Date: Fri, 16 Oct 2026 09:00:43 -0400 Subject: [PATCH 1/2] fix(ui): show the physical page position under a labelled page box (#2834) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When the current page's label is not its page number (front matter numbered i, ii, then 1, 2 …), the rail shows "3/180" under the page box instead of only the page count, with "Page 3 of 180" on hover. It falls back to the count when the text would not fit the rail. The page box itself already shows and accepts labels since #1667 (0.8.0 showed the physical index). Co-Authored-By: Claude Opus 5.5 --- crates/ui-egui/src/chrome.rs | 31 ++++++++++++++++++++++++++++++- crates/ui-egui/tests/viewer.rs | 3 +++ parity/acrobat-features.toml | 2 +- 3 files changed, 34 insertions(+), 2 deletions(-) diff --git a/crates/ui-egui/src/chrome.rs b/crates/ui-egui/src/chrome.rs index e01d752c4..e1ff1f4b6 100644 --- a/crates/ui-egui/src/chrome.rs +++ b/crates/ui-egui/src/chrome.rs @@ -753,7 +753,14 @@ pub fn right_rail(app: &mut PdfCraftApp, ui: &mut egui::Ui) { view.view_history(forward); } } - ui.label(egui::RichText::new(page_count.to_string()).font(theme::regular(11.0)).color(t.text_muted)); + let font = theme::regular(11.0); + let mut position = page_position(view.current, page_count, labels.get(view.current).map_or("", String::as_str)); + if widgets::text_width(ui, &position, &font) > ui.available_width() { + position = page_count.to_string(); + } + let of = + crate::i18n::fmt(tl!("Page {p} of {n}"), &[("p", &view.current.saturating_add(1).to_string()), ("n", &page_count.to_string())]); + ui.label(egui::RichText::new(position).font(font).color(t.text_muted)).on_hover_text(of); let page_input_id = view.page_input_id(); // Consume replacement selection once, including when the editor has lost focus. let reselect = std::mem::take(&mut view.page_input_reselect); @@ -795,6 +802,13 @@ pub fn right_rail(app: &mut PdfCraftApp, ui: &mut egui::Ui) { }); } +/// What the rail shows under the page box: the page count, or, when the current page's label is +/// not its physical number (front matter numbered i, ii, …), its position as "3/180" (#2834). +fn page_position(current: usize, count: usize, label: &str) -> String { + let number = current.saturating_add(1).to_string(); + if label.is_empty() || label == number || current >= count { count.to_string() } else { format!("{number}/{count}") } +} + /// View ▸ Page display and the rail's Page display menu: the layouts and the cover page. /// Returns the command a click asks for, for the caller to run. fn page_display_menu(ui: &mut egui::Ui, view: &DocView) -> Option<&'static str> { @@ -857,6 +871,21 @@ fn rail_view_menu(ui: &mut egui::Ui, view: &mut DocView) -> Option<&'static str> picked } +#[cfg(test)] +mod page_position_tests { + use super::page_position; + + #[test] + fn position_shows_only_when_the_label_is_not_the_page_number() { + assert_eq!(page_position(0, 180, "i"), "1/180"); + assert_eq!(page_position(2, 180, "1"), "3/180"); + assert_eq!(page_position(2, 180, "3"), "180"); + assert_eq!(page_position(2, 180, ""), "180"); + assert_eq!(page_position(0, 0, "i"), "0"); + assert_eq!(page_position(usize::MAX, 3, "x"), "3"); + } +} + #[cfg(test)] mod tab_widths { use super::{MAC_CONTENT_LEFT, MAC_LIGHT, MAC_LIGHT_PITCH, MAC_LIGHTS_LEFT, MAC_TITLE_BAR, tab_cap}; diff --git a/crates/ui-egui/tests/viewer.rs b/crates/ui-egui/tests/viewer.rs index b15469485..9d5cbcede 100644 --- a/crates/ui-egui/tests/viewer.rs +++ b/crates/ui-egui/tests/viewer.rs @@ -330,6 +330,9 @@ fn layouts_fit_height_labels_and_system_theme() { assert_eq!(labels[1], "ii"); assert!(h.state_mut().views[0].go_to_typed("ii", &labels)); assert_eq!(h.state().views[0].current, 1); + // Under the box, the physical position, since "ii" does not say which page it is (#2834). + h.run_steps(2); + h.get(By::new().label(&format!("2/{}", labels.len()))); assert!(!h.state_mut().views[0].go_to_typed("xx", &labels)); // Follow the system theme. h.state_mut().set_option("theme", "system").unwrap(); diff --git a/parity/acrobat-features.toml b/parity/acrobat-features.toml index 8d7fabed1..369cb8b80 100644 --- a/parity/acrobat-features.toml +++ b/parity/acrobat-features.toml @@ -1155,7 +1155,7 @@ status = "shipped" commands = [] tools = [] evidence = ["crates/ui-egui/tests/viewer.rs::layouts_fit_height_labels_and_system_theme"] -notes = "the page box takes labels (iv, A-1) before numbers" +notes = "the page box shows the current page's label and takes labels (iv, A-1) before numbers; where the label is not the page number the rail shows the physical position under it (3/180, dropped to the page count when it does not fit). Not yet: a preference to show physical numbers only, and labels in the organize bar's Page n of m" [[feature]] id = "view.view-history" From 563a719f03f614987b5c6babd435cdb86f4d0bc9 Mon Sep 17 00:00:00 2001 From: Christoph Ortenburg Date: Mon, 19 Oct 2026 14:48:31 -0400 Subject: [PATCH 2/2] fix(ui): the page tooltip stays in range on an empty document (#2834) Co-Authored-By: Claude Opus 5.5 --- crates/ui-egui/src/chrome.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/crates/ui-egui/src/chrome.rs b/crates/ui-egui/src/chrome.rs index e1ff1f4b6..dc26549cc 100644 --- a/crates/ui-egui/src/chrome.rs +++ b/crates/ui-egui/src/chrome.rs @@ -758,8 +758,9 @@ pub fn right_rail(app: &mut PdfCraftApp, ui: &mut egui::Ui) { if widgets::text_width(ui, &position, &font) > ui.available_width() { position = page_count.to_string(); } - let of = - crate::i18n::fmt(tl!("Page {p} of {n}"), &[("p", &view.current.saturating_add(1).to_string()), ("n", &page_count.to_string())]); + // Out of range (an empty document), like `page_position`: "Page 0 of 0", never past the end. + let shown = if view.current < page_count { view.current + 1 } else { page_count }; + let of = crate::i18n::fmt(tl!("Page {p} of {n}"), &[("p", &shown.to_string()), ("n", &page_count.to_string())]); ui.label(egui::RichText::new(position).font(font).color(t.text_muted)).on_hover_text(of); let page_input_id = view.page_input_id(); // Consume replacement selection once, including when the editor has lost focus.