diff --git a/crates/ui-egui/src/widgets/look_tests.rs b/crates/ui-egui/src/widgets/look_tests.rs index 17a2288d1..1f9275008 100644 --- a/crates/ui-egui/src/widgets/look_tests.rs +++ b/crates/ui-egui/src/widgets/look_tests.rs @@ -468,3 +468,31 @@ fn a_held_spinner_arrow_repeats() { frame(&ctx, 1.8, vec![], &mut add); assert_eq!(value.get(), 9.0, "letting go doesn't step once more"); } + +/// The Kerning field reads `(10+5)` as 15 whether it shows a manual value (`12`) or an automatic +/// one (`(12)`), and refuses `(10+5)*2` either way. +#[test] +fn kerning_reads_parentheses_around_its_text_with_a_manual_value_too() { + let typed = |automatic: bool, text: &str| { + let ctx = themed(Default::default()); + let picked = std::cell::Cell::new(None); + let mut add = |ui: &mut Ui| { + ui.horizontal(|ui| { + if let Some(p) = spin_kerning(ui, "kern", Some(12.0), Some(automatic), Some(false), "Optical", automatic, 100.0, &[]) { + picked.set(Some(p)); + } + }); + }; + arm_field_focus(&ctx, "kern"); + frame(&ctx, 0.0, vec![], &mut add); + frame(&ctx, 0.1, vec![], &mut add); + let enter = |pressed| egui::Event::Key { key: egui::Key::Enter, physical_key: None, pressed, repeat: false, modifiers: Default::default() }; + frame(&ctx, 0.2, vec![egui::Event::Text(text.into()), enter(true), enter(false)], &mut add); + frame(&ctx, 0.3, vec![], &mut add); + picked.get() + }; + for automatic in [false, true] { + assert_eq!(typed(automatic, "(10+5)"), Some(SpinPick::Value(15.0)), "automatic: {automatic}"); + assert_eq!(typed(automatic, "(10+5)*2"), None, "automatic: {automatic}"); + } +} diff --git a/crates/ui-egui/src/widgets/numeric.rs b/crates/ui-egui/src/widgets/numeric.rs index 56ace75b8..847b3b0ea 100644 --- a/crates/ui-egui/src/widgets/numeric.rs +++ b/crates/ui-egui/src/widgets/numeric.rs @@ -433,9 +433,8 @@ pub fn mixed_field_named( bounded_field(ui, id, label, name, value, suffix, decimals, width, &ANY, None, false, false) } -/// [`mixed_field`] whose ↑/↓, wheel and scrub stop at `bounds`; ↑/↓ and the wheel take `step`'s steps -/// when it is given (see [`SliderValue::step`]). Armed with id salt `id` ([`arm_field_focus`]), it -/// takes the keyboard focus with its value selected. +/// [`bounded_field_reading`] that reads one pair of parentheses around its text only while it shows +/// its value in parentheses. #[allow(clippy::too_many_arguments)] fn bounded_field( ui: &mut Ui, @@ -450,11 +449,34 @@ fn bounded_field( step: Option f64>, parentheses: bool, live: bool, +) -> Option { + bounded_field_reading(ui, id, label, name, value, suffix, decimals, width, bounds, step, parentheses, parentheses, live) +} + +/// [`mixed_field`] whose ↑/↓, wheel and scrub stop at `bounds`; ↑/↓ and the wheel take `step`'s steps +/// when it is given (see [`SliderValue::step`]). Armed with id salt `id` ([`arm_field_focus`]), it +/// takes the keyboard focus with its value selected. With `parentheses` it shows its value as +/// `(12)`; with `read_parentheses` it reads typed text as [`field_number`] does with its Kerning flag. +#[allow(clippy::too_many_arguments)] +fn bounded_field_reading( + ui: &mut Ui, + id: impl std::hash::Hash, + label: Option, + name: Option<&str>, + value: Option, + suffix: &str, + decimals: usize, + width: f32, + bounds: &RangeInclusive, + step: Option f64>, + parentheses: bool, + read_parentheses: bool, + live: bool, ) -> Option { let armed = take_armed_focus(ui, &id); let id = id_with(ui.scope_id(), id); let show = |value: f64| field_text(value, suffix, decimals); - let read = |buf: &str| field_number(buf, suffix, parentheses); + let read = |buf: &str| field_number(buf, suffix, read_parentheses); let shown = value.map(|v| if parentheses { format!("({})", show(v)) } else { show(v) }).unwrap_or_default(); take_dialog_focus(ui, id, &shown); if armed { @@ -677,7 +699,9 @@ pub fn spin_plain_named( .and_then(SpinPick::value) } -/// Kerning's numeric field and automatic method choices. +/// Kerning's numeric field and automatic method choices. With `parentheses` the field shows its +/// value as `(12)`; typed text such as `(10+5)` reads with one pair of parentheses around it either +/// way. #[allow(clippy::too_many_arguments)] pub fn spin_kerning( ui: &mut Ui, @@ -704,7 +728,7 @@ pub fn spin_kerning( presets, &[], &|v| format!("{v}"), - &mut |ui, fw, label| bounded_field(ui, id, label, None, value, "", 0, fw, &(-1000.0..=f64::INFINITY), None, parentheses, false), + &mut |ui, fw, label| bounded_field_reading(ui, id, label, None, value, "", 0, fw, &(-1000.0..=f64::INFINITY), None, parentheses, true, false), ) }