This commit is contained in:
parent
5c5f4d8b49
commit
3c771e0395
|
|
@ -364,11 +364,12 @@ pub(crate) fn section(app: &mut PdfCraftApp, ui: &mut egui::Ui) {
|
|||
18.0,
|
||||
egui::Color32::from_rgb(0xE0, 0x3E, 0x3E),
|
||||
);
|
||||
ui.painter().text(rect.min + vec2(62.0, 19.0), Align2::LEFT_CENTER, crate::bidi::visual(&f.name), theme::medium(13.0), t.text);
|
||||
let size = crate::panels::human_size(usize::try_from(f.size).unwrap_or(usize::MAX));
|
||||
let when = f.modified.map(crate::combine_ui::ago).unwrap_or_default();
|
||||
let detail = if when.is_empty() { size } else { format!("{when} · {size}") };
|
||||
ui.painter().text(rect.right_center() - vec2(12.0, 0.0), Align2::RIGHT_CENTER, detail, theme::regular(12.0), t.text_muted);
|
||||
let detail = ui.painter().text(rect.right_center() - vec2(12.0, 0.0), Align2::RIGHT_CENTER, detail, theme::regular(12.0), t.text_muted);
|
||||
let width = detail.left() - 16.0 - (rect.left() + 62.0);
|
||||
widgets::row_text(ui, rect.min + vec2(62.0, 19.0), crate::bidi::visual(&f.name), theme::medium(13.0), t.text, width);
|
||||
if resp.on_hover_text(&f.path).clicked() {
|
||||
open = Some(f.path.clone());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -123,16 +123,18 @@ pub fn show(app: &mut PdfCraftApp, ui: &mut egui::Ui) {
|
|||
22.0,
|
||||
egui::Color32::from_rgb(0xE0, 0x3E, 0x3E),
|
||||
);
|
||||
ui.painter().text(rect.min + vec2(46.0, 15.0), Align2::LEFT_CENTER, crate::bidi::visual(&r.name), theme::medium(13.5), t.text);
|
||||
ui.painter().text(rect.min + vec2(46.0, 32.0), Align2::LEFT_CENTER, crate::bidi::visual(&r.path), theme::regular(11.0), t.text_faint);
|
||||
ui.painter().text(
|
||||
let detail = ui.painter().text(
|
||||
rect.right_center() - vec2(12.0, 0.0),
|
||||
Align2::RIGHT_CENTER,
|
||||
format!("{} {} · {}", r.pages, tl!("pages"), human_size(r.size)),
|
||||
theme::regular(12.0),
|
||||
t.text_muted,
|
||||
);
|
||||
if resp.clicked() {
|
||||
// The name and path stop short of the page count; hovering shows the whole path.
|
||||
let width = detail.left() - 16.0 - (rect.left() + 46.0);
|
||||
widgets::row_text(ui, rect.min + vec2(46.0, 15.0), crate::bidi::visual(&r.name), theme::medium(13.5), t.text, width);
|
||||
widgets::row_text(ui, rect.min + vec2(46.0, 32.0), crate::bidi::visual(&r.path), theme::regular(11.0), t.text_faint, width);
|
||||
if resp.on_hover_text(&r.path).clicked() {
|
||||
open = Some(r.path.clone());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -81,6 +81,16 @@ pub fn section_title(ui: &mut egui::Ui, text: &str) {
|
|||
ui.add_space(2.0);
|
||||
}
|
||||
|
||||
/// Paint one line of `text` left-aligned and vertically centred on `pos`, cut with "…" so it is
|
||||
/// at most `max_width` wide: a long file name or path stays inside its row (#425).
|
||||
pub fn row_text(ui: &egui::Ui, pos: egui::Pos2, text: impl Into<String>, font: egui::FontId, color: Color32, max_width: f32) {
|
||||
let mut job = egui::text::LayoutJob::simple_singleline(text.into(), font, color);
|
||||
job.wrap = egui::text::TextWrapping::truncate_at_width(max_width.max(0.0));
|
||||
let galley = ui.painter().layout_job(job);
|
||||
let rect = Align2::LEFT_CENTER.anchor_size(pos, galley.size());
|
||||
ui.painter().galley(rect.min, galley, color);
|
||||
}
|
||||
|
||||
/// Transient message at the bottom centre.
|
||||
pub fn toast(app: &mut PdfCraftApp, ctx: &egui::Context) {
|
||||
let Some((msg, start)) = app.toast.clone() else { return };
|
||||
|
|
|
|||
|
|
@ -197,6 +197,32 @@ fn show_more_reveals_the_older_pdfs() {
|
|||
h.get_by_label("Show less");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_long_pdf_name_is_cut_before_its_date_and_size() {
|
||||
let dir = TempFolder::new("long");
|
||||
// Short enough for Windows' 260-character paths under the temp folder.
|
||||
let name = format!("{}.pdf", "Signed contract with a long name ".repeat(4));
|
||||
dir.file(&name, FIXTURE, Duration::from_secs(10));
|
||||
let folder = dir.path();
|
||||
let mut h = harness(move |app| {
|
||||
app.pin_folder(&folder);
|
||||
});
|
||||
h.run_steps(2);
|
||||
let text: Vec<(String, bool, egui::Rect)> = h
|
||||
.output()
|
||||
.shapes
|
||||
.iter()
|
||||
.filter_map(|c| match &c.shape {
|
||||
egui::Shape::Text(t) => Some((t.galley.text().to_owned(), t.galley.elided, t.visual_bounding_rect())),
|
||||
_ => None,
|
||||
})
|
||||
.collect();
|
||||
let (_, cut, rect) = text.iter().find(|(s, ..)| *s == name).expect("the PDF is listed");
|
||||
let detail = text.iter().find(|(s, _, r)| s.contains('·') && r.y_range().contains(rect.center().y)).expect("its row shows the date and size").2;
|
||||
assert!(*cut, "the name is cut short");
|
||||
assert!(rect.right() < detail.left(), "the name ends before the date and size");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pinning_is_limited_and_never_duplicates() {
|
||||
let mut app = PdfCraftApp::new();
|
||||
|
|
|
|||
|
|
@ -37,6 +37,36 @@ fn home_shows_welcome_and_tools() {
|
|||
h.get_by_label("Open file");
|
||||
}
|
||||
|
||||
/// Every piece of text painted on the last frame: its whole text, whether it was cut with "…",
|
||||
/// and where it was drawn.
|
||||
fn painted_text(h: &Harness<'static, PdfCraftApp>) -> Vec<(String, bool, egui::Rect)> {
|
||||
h.output()
|
||||
.shapes
|
||||
.iter()
|
||||
.filter_map(|c| match &c.shape {
|
||||
egui::Shape::Text(t) => Some((t.galley.text().to_owned(), t.galley.elided, t.visual_bounding_rect())),
|
||||
_ => None,
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn long_recent_names_and_paths_are_cut_before_the_page_count() {
|
||||
let name = format!("{}.pdf", "Quarterly report final version ".repeat(10));
|
||||
let path = format!("/{}/{name}", "A folder with a long name".repeat(8));
|
||||
let h = harness({
|
||||
let (name, path) = (name.clone(), path.clone());
|
||||
move |app| app.recent.push(pdfcraft_ui_egui::RecentFile { name, path, pages: 7, size: 2048 })
|
||||
});
|
||||
let text = painted_text(&h);
|
||||
let detail = text.iter().find(|(s, ..)| s.starts_with("7 pages")).expect("the row shows its page count").2;
|
||||
for whole in [&name, &path] {
|
||||
let (_, cut, rect) = text.iter().find(|(s, ..)| s == whole).expect("the row shows the name and the path");
|
||||
assert!(*cut, "{whole:?} is cut short");
|
||||
assert!(rect.right() < detail.left(), "{whole:?} ends before the page count");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn every_catalog_tool_is_listed_after_view_more() {
|
||||
let mut h = harness(|_| {});
|
||||
|
|
|
|||
Loading…
Reference in New Issue