From 922399b9a21a81a6e8dd73a0fc472616eb480f15 Mon Sep 17 00:00:00 2001 From: Nils Pukropp Date: Fri, 9 Oct 2026 02:18:47 +0200 Subject: [PATCH] fix(gui): even breadcrumb spacing, no invented hyphens in tile names MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The current folder in the breadcrumb trail was a bare label, so the "›" before it hugged it while the ones between buttons sat in their padding. One helper now builds the separator and the current segment for My Files, Shared with me and Computers, with a flat button's side padding. Grid tile names broke mid-word with a hyphen that is not in the name ("SteamSetup.e-xe"); turn Pango's inserted hyphens off. --- crates/pdfs-gui/resources/style.css | 3 +++ crates/pdfs-gui/src/app/main.rs | 1 + crates/pdfs-gui/src/app/pages/browser.rs | 11 ++-------- crates/pdfs-gui/src/app/pages/devices.rs | 11 ++-------- crates/pdfs-gui/src/app/pages/shared.rs | 11 ++-------- crates/pdfs-gui/src/app/widgets/crumb.rs | 21 ++++++++++++++++++++ crates/pdfs-gui/src/app/widgets/file_list.rs | 7 ++++++- crates/pdfs-gui/src/app/widgets/mod.rs | 1 + 8 files changed, 38 insertions(+), 28 deletions(-) create mode 100644 crates/pdfs-gui/src/app/widgets/crumb.rs diff --git a/crates/pdfs-gui/resources/style.css b/crates/pdfs-gui/resources/style.css index 957d114..e46a333 100644 --- a/crates/pdfs-gui/resources/style.css +++ b/crates/pdfs-gui/resources/style.css @@ -48,6 +48,9 @@ .badge-cloud { color: color-mix(in srgb, currentColor 55%, transparent); } .badge-issue { color: var(--error-color); } .browser-statusbar { background-color: alpha(currentColor, 0.025); } +/* The folder on screen, last in the breadcrumb trail: a flat button's side + * padding, so the "›" before it is spaced like the ones between buttons. */ +.crumb-current { padding: 0 10px; } scale.browser-status-meter trough { min-width: 104px; min-height: 6px; } .bulk-bar { padding: 6px 8px; border-radius: 12px; background: color-mix(in srgb, var(--accent-bg-color) 12%, transparent); } .dropzone { border: 2px dashed alpha(currentColor, 0.25); border-radius: 16px; padding: 28px 18px; transition: background 160ms ease, border-color 160ms ease; } diff --git a/crates/pdfs-gui/src/app/main.rs b/crates/pdfs-gui/src/app/main.rs index 9bf08a5..8feb958 100644 --- a/crates/pdfs-gui/src/app/main.rs +++ b/crates/pdfs-gui/src/app/main.rs @@ -34,6 +34,7 @@ use pages::verify::*; use reload::{LoadTicket, Loader, replace_items}; use theme::{load_resources, proton_theme_active, set_proton_theme}; use widgets::compat::*; +use widgets::crumb::*; use widgets::details::*; use widgets::file_list::*; use widgets::menu::*; diff --git a/crates/pdfs-gui/src/app/pages/browser.rs b/crates/pdfs-gui/src/app/pages/browser.rs index d9c4e41..c7d2521 100644 --- a/crates/pdfs-gui/src/app/pages/browser.rs +++ b/crates/pdfs-gui/src/app/pages/browser.rs @@ -1220,9 +1220,7 @@ pub(crate) fn repaint_crumb(ui: &Rc, path: &str) { )); let mut acc = String::new(); for (i, seg) in segments.iter().enumerate() { - let sep = gtk4::Label::new(Some("›")); - sep.add_css_class("dim-label"); - ui.browser.crumb.append(&sep); + ui.browser.crumb.append(&crumb_separator()); acc = if acc.is_empty() { seg.to_string() } else { @@ -1237,12 +1235,7 @@ pub(crate) fn repaint_crumb(ui: &Rc, path: &str) { /// flat button that navigates to `target` (clearing any active search first). pub(crate) fn crumb_node(ui: &Rc, label: &str, target: &str, current: bool) -> gtk4::Widget { if current { - let l = gtk4::Label::builder() - .label(label) - .ellipsize(gtk4::pango::EllipsizeMode::Start) - .build(); - l.add_css_class("heading"); - return l.upcast(); + return crumb_current(label); } let button = gtk4::Button::builder().label(label).build(); button.add_css_class("flat"); diff --git a/crates/pdfs-gui/src/app/pages/devices.rs b/crates/pdfs-gui/src/app/pages/devices.rs index 14e26d7..cdd28c7 100644 --- a/crates/pdfs-gui/src/app/pages/devices.rs +++ b/crates/pdfs-gui/src/app/pages/devices.rs @@ -487,9 +487,7 @@ fn repaint_device_crumb(ui: &Rc, nav: &[(String, String)]) { nav.is_empty(), )); for (i, (_, name)) in nav.iter().enumerate() { - let sep = gtk4::Label::new(Some("›")); - sep.add_css_class("dim-label"); - crumb.append(&sep); + crumb.append(&crumb_separator()); crumb.append(&device_crumb_node(ui, name, i + 1, i + 1 == nav.len())); } } @@ -498,12 +496,7 @@ fn repaint_device_crumb(ui: &Rc, nav: &[(String, String)]) { /// that goes back up to `depth` levels below the device list. fn device_crumb_node(ui: &Rc, label: &str, depth: usize, current: bool) -> gtk4::Widget { if current { - let l = gtk4::Label::builder() - .label(label) - .ellipsize(gtk4::pango::EllipsizeMode::Start) - .build(); - l.add_css_class("heading"); - return l.upcast(); + return crumb_current(label); } let button = gtk4::Button::builder().label(label).build(); button.add_css_class("flat"); diff --git a/crates/pdfs-gui/src/app/pages/shared.rs b/crates/pdfs-gui/src/app/pages/shared.rs index 197d96b..efc1352 100644 --- a/crates/pdfs-gui/src/app/pages/shared.rs +++ b/crates/pdfs-gui/src/app/pages/shared.rs @@ -484,9 +484,7 @@ fn repaint_shared_crumb(ui: &Rc, nav: &[(String, String)]) { nav.is_empty(), )); for (i, (_, name)) in nav.iter().enumerate() { - let sep = gtk4::Label::new(Some("›")); - sep.add_css_class("dim-label"); - crumb.append(&sep); + crumb.append(&crumb_separator()); crumb.append(&shared_crumb_node(ui, name, i + 1, i + 1 == nav.len())); } } @@ -495,12 +493,7 @@ fn repaint_shared_crumb(ui: &Rc, nav: &[(String, String)]) { /// that goes back up to `depth` folders below the top level. fn shared_crumb_node(ui: &Rc, label: &str, depth: usize, current: bool) -> gtk4::Widget { if current { - let l = gtk4::Label::builder() - .label(label) - .ellipsize(gtk4::pango::EllipsizeMode::Start) - .build(); - l.add_css_class("heading"); - return l.upcast(); + return crumb_current(label); } let button = gtk4::Button::builder().label(label).build(); button.add_css_class("flat"); diff --git a/crates/pdfs-gui/src/app/widgets/crumb.rs b/crates/pdfs-gui/src/app/widgets/crumb.rs new file mode 100644 index 0000000..f99fbdf --- /dev/null +++ b/crates/pdfs-gui/src/app/widgets/crumb.rs @@ -0,0 +1,21 @@ +use crate::*; + +/// The "›" between two breadcrumb segments. +pub(crate) fn crumb_separator() -> gtk4::Label { + let sep = gtk4::Label::new(Some("›")); + sep.add_css_class("dim-label"); + sep +} + +/// The last breadcrumb segment, the folder on screen: a heading rather than a +/// button. It carries a flat button's side padding (`.crumb-current`), so the +/// "›" before it sits as far from it as from the button before. +pub(crate) fn crumb_current(label: &str) -> gtk4::Widget { + let l = gtk4::Label::builder() + .label(label) + .ellipsize(gtk4::pango::EllipsizeMode::Start) + .build(); + l.add_css_class("heading"); + l.add_css_class("crumb-current"); + l.upcast() +} diff --git a/crates/pdfs-gui/src/app/widgets/file_list.rs b/crates/pdfs-gui/src/app/widgets/file_list.rs index 3007ec9..dac98cf 100644 --- a/crates/pdfs-gui/src/app/widgets/file_list.rs +++ b/crates/pdfs-gui/src/app/widgets/file_list.rs @@ -132,8 +132,13 @@ impl FileList { // and the grid collapses to a single column. Allowing a mid-word // break is what keeps the two-line-then-ellipsis budget below // enforceable for *every* name rather than only the ones that - // happen to have spaces. + // happen to have spaces. Pango marks such a break with a hyphen + // that is not in the name ("SteamSetup.e-xe"); a file name is + // not prose, so break it bare, as Nautilus does. + let no_hyphens = gtk4::pango::AttrList::new(); + no_hyphens.insert(gtk4::pango::AttrInt::new_insert_hyphens(false)); let label = gtk4::Label::builder() + .attributes(&no_hyphens) .ellipsize(gtk4::pango::EllipsizeMode::End) .justify(gtk4::Justification::Center) .max_width_chars(13) diff --git a/crates/pdfs-gui/src/app/widgets/mod.rs b/crates/pdfs-gui/src/app/widgets/mod.rs index 3e4d1a4..e0f5620 100644 --- a/crates/pdfs-gui/src/app/widgets/mod.rs +++ b/crates/pdfs-gui/src/app/widgets/mod.rs @@ -1,4 +1,5 @@ pub(crate) mod compat; +pub(crate) mod crumb; pub(crate) mod details; pub(crate) mod file_list; pub(crate) mod menu;