From a30dde2225925abe55366c02cb9532a1c9d0c645 Mon Sep 17 00:00:00 2001 From: Eric Kaden <608341+EricKaden@users.noreply.github.com> Date: Mon, 19 Oct 2026 12:58:15 -0400 Subject: [PATCH] M6: the date picker follows a whole date typed while it is open (#3393) The calendar took its month once, when it opened, so a date typed while it was open showed only after leaving the field and coming back. It now moves to a date as soon as the text becomes one, and stays on the month it shows while the text is half typed or unchanged, so its arrows still turn the months. --- crates/ui-egui/src/editing.rs | 1 + crates/ui-egui/src/forms_ui.rs | 20 ++++++++++++++++---- crates/ui-egui/tests/forms.rs | 33 +++++++++++++++++++++++++++++++++ parity/acrobat-features.toml | 4 ++-- 4 files changed, 52 insertions(+), 6 deletions(-) diff --git a/crates/ui-egui/src/editing.rs b/crates/ui-egui/src/editing.rs index e554d7a1b0..91480ac7b5 100644 --- a/crates/ui-egui/src/editing.rs +++ b/crates/ui-egui/src/editing.rs @@ -1420,6 +1420,7 @@ mod revert_draft_tests { press: None, calendar: None, calendar_rect: None, + calendar_text: None, } } diff --git a/crates/ui-egui/src/forms_ui.rs b/crates/ui-egui/src/forms_ui.rs index 8020e868b2..612b985e65 100644 --- a/crates/ui-egui/src/forms_ui.rs +++ b/crates/ui-egui/src/forms_ui.rs @@ -38,6 +38,9 @@ pub struct Focus { /// Date fields: the month the calendar shows (year, month 1–12), and where it was drawn. pub calendar: Option<(i32, u32)>, pub calendar_rect: Option, + /// The text the calendar last saw, so it moves to a typed date once, when the typing becomes + /// a whole date, and otherwise keeps the month its arrows turned to. + pub calendar_text: Option, } #[derive(Clone, Debug, Default)] @@ -90,6 +93,7 @@ fn open_focus(f: &FormField, widget: usize) -> Focus { press: None, calendar: None, calendar_rect: None, + calendar_text: None, } } @@ -255,11 +259,19 @@ const MONTHS: [&str; 12] = ["January", "February", "March", "April", "May", "Jun fn calendar(ctx: &egui::Context, view: &mut DocView, field: egui::Rect, fmt: &str, today: (i64, u32, u32)) -> Option { use pdfcraft_engine::form_scripts::{DateTime, format_date, parse_date}; let fx = view.forms.focus.as_mut()?; - let (mut y, mut m) = fx.calendar.unwrap_or_else(|| match parse_date(&fx.text, fmt) { - Some(d) => (d.y, d.m), - None => (today.0 as i32, today.1), - }); let current = parse_date(&fx.text, fmt); + // A whole date typed since the last frame moves the calendar to it; half a date, or text + // that hasn't changed, leaves it on the month it shows (the one the arrows turned to). + let changed = fx.calendar_text.as_deref() != Some(fx.text.as_str()); + let (mut y, mut m) = match (fx.calendar, current) { + (Some(_), Some(d)) if changed => (d.y, d.m), + (Some(shown), _) => shown, + (None, Some(d)) => (d.y, d.m), + (None, None) => (today.0 as i32, today.1), + }; + if changed { + fx.calendar_text = Some(fx.text.clone()); + } let mut picked = None; let area = egui::Area::new(egui::Id::new(("date-picker", view.id.0))) .order(egui::Order::Foreground) diff --git a/crates/ui-egui/tests/forms.rs b/crates/ui-egui/tests/forms.rs index 96a0a6a11e..bd7df61872 100644 --- a/crates/ui-egui/tests/forms.rs +++ b/crates/ui-egui/tests/forms.rs @@ -185,6 +185,39 @@ fn date_fields_offer_a_calendar() { assert_eq!(value(&h, "due"), vec![format!("{nm:02}/15/{ny}")], "picked in the field's format"); } +/// The calendar used to keep the month it opened on, so a date typed while it was open showed +/// only after leaving the field and coming back. +#[test] +fn the_calendar_follows_a_complete_date_typed_while_it_is_open() { + use egui_kittest::kittest::Queryable; + let mut h = harness(); + h.state_mut().apply_edit(pdfcraft_engine::Edit::AddField { + page: 0, + rect: [50.0, 40.0, 200.0, 60.0], + kind: pdfcraft_engine::NewField::Date, + name: Some("due".into()), + }); + h.run_steps(4); + click_field(&mut h, "due", 0); + let (y, m, _) = h.state().session.today(); + let month = + ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"][(m - 1) as usize]; + h.get_by_label(&format!("{month} {y}")); + // Half a date leaves the calendar where it is. + h.event(egui::Event::Text("03/1".into())); + h.run_steps(2); + h.get_by_label(&format!("{month} {y}")); + // The whole date moves it there. + h.event(egui::Event::Text("4/2025".into())); + h.run_steps(2); + h.get_by_label("March 2025"); + // The arrows still turn the months, and the calendar stays on their month while the text + // doesn't change. + h.get_by_label("›").click(); + h.run_steps(3); + h.get_by_label("April 2025"); +} + #[test] fn lithuanian_calendar_localizes_months_and_weekdays_without_changing_field_values() { use egui_kittest::kittest::Queryable; diff --git a/parity/acrobat-features.toml b/parity/acrobat-features.toml index 58cc527eaf..1c68d23335 100644 --- a/parity/acrobat-features.toml +++ b/parity/acrobat-features.toml @@ -4620,8 +4620,8 @@ milestone = "M6" status = "shipped" commands = [] tools = ["form_fill"] -evidence = ["crates/ui-egui/tests/forms.rs::date_fields_offer_a_calendar"] -notes = "a month calendar under date fields; the pick is written in the field's own date format" +evidence = ["crates/ui-egui/tests/forms.rs::date_fields_offer_a_calendar", "crates/ui-egui/tests/forms.rs::the_calendar_follows_a_complete_date_typed_while_it_is_open"] +notes = "a month calendar under date fields; the pick is written in the field's own date format; it opens on the field's date and moves to a whole date typed while it is open, staying on the month its arrows turned to otherwise" [[feature]] id = "form.auto-complete"