Character: Kerning reads (10+5)*2 as nothing instead of 10+5*2

Numeric fields dropped every parenthesis before reading a value, so
(10+5)*2 typed into a field committed 20. Only the Kerning field, which
shows its automatic value as (12), now drops one pair of parentheses
around the whole text. Parentheses anywhere else are refused, and fields
without that display refuse them too.
This commit is contained in:
dotCooCoo
2026-11-04 18:56:36 +07:00
committed by bflatastic
parent 42de898d01
commit a7266dd10a
2 changed files with 41 additions and 8 deletions
+25 -1
View File
@@ -57,7 +57,7 @@ pub use numeric::{
spin_field_auto, spin_field_auto_named, spin_field_named, spin_field_stops_named, spin_kerning, spin_plain, spin_plain_named,
};
#[cfg(test)]
use numeric::{decimal_point, share_of, spinner_step, step_through, step_to_multiple, within_a_millionth};
use numeric::{decimal_point, field_number, share_of, spinner_step, step_through, step_to_multiple, within_a_millionth};
pub use panel_chrome::{bottom_bar, layout_button, list_box, orientation_button, tab_bar};
pub(crate) use text::{
arm_field_focus, dialog_focus_flag, dialog_reject_commit_flag, disarm_field_focus, enter_modifiers, focus_field, own_field_shift_enter,
@@ -464,6 +464,30 @@ mod decimal_point_tests {
}
}
#[cfg(test)]
mod field_number_tests {
use super::*;
/// Kerning drops one pair of parentheses around its whole text, so its automatic value `(12)`
/// reads as 12. Parentheses inside the text are refused rather than dropped, which would read
/// `(10+5)*2` as `10+5*2`, and fields without the Kerning flag refuse parentheses too.
#[test]
fn only_kerning_drops_one_pair_of_parentheses_around_the_text() {
assert_eq!(field_number("(12)", "", true), Some(12.0));
assert_eq!(field_number(" (-25) ", "", true), Some(-25.0));
assert_eq!(field_number("(10+5)", "", true), Some(15.0));
assert_eq!(field_number("12", "", true), Some(12.0));
for text in ["(10+5)*2", "2*(10+5)", "(10)+(5)", "((12))", "(12", "12)"] {
assert_eq!(field_number(text, "", true), None, "{text}");
}
for text in ["(12)", "(10+5)*2"] {
assert_eq!(field_number(text, "", false), None, "{text} without the Kerning flag");
}
assert_eq!(field_number("45*2°", "°", false), Some(90.0));
assert_eq!(field_number("50% / 2", "%", false), Some(25.0));
}
}
#[cfg(test)]
mod menu_room_tests {
use super::*;
+16 -7
View File
@@ -454,13 +454,7 @@ fn bounded_field(
let armed = take_armed_focus(ui, &id);
let id = id_with(ui.scope_id(), id);
let show = |value: f64| field_text(value, suffix, decimals);
// The suffix (and %, °) may follow any operand: `45*2°`, `50% / 2`.
let read = |buf: &str| {
let suffix = suffix.trim();
let buf = decimal_point(buf);
let bare = if suffix.is_empty() { buf.to_string() } else { buf.replace(suffix, "") };
vectorcraft_doc::parse_number(&bare.replace(['%', '°', '(', ')'], ""))
};
let read = |buf: &str| field_number(buf, suffix, 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 {
@@ -491,6 +485,21 @@ fn bounded_field(
}
}
/// The number text typed into a [`bounded_field`] with `suffix` reads as. The suffix, `%` and `°`
/// may follow any operand: `45*2°`, `50% / 2`. With `parentheses` (Kerning, which shows its
/// automatic value as `(12)`), one pair of parentheses around the whole text is dropped first, so
/// `(12)` reads as 12. Any other parentheses are refused: `(10+5)*2` reads as nothing, not as
/// `10+5*2`.
pub(super) fn field_number(buf: &str, suffix: &str, parentheses: bool) -> Option<f64> {
let suffix = suffix.trim();
let buf = decimal_point(buf);
let bare = if suffix.is_empty() { buf.to_string() } else { buf.replace(suffix, "") };
let bare = bare.replace(['%', '°'], "");
let bare = bare.trim();
let bare = if parentheses { bare.strip_prefix('(').and_then(|b| b.strip_suffix(')')).unwrap_or(bare) } else { bare };
vectorcraft_doc::parse_number(bare)
}
/// The text [`plain_field`] shows for `value`: at most `decimals` places, without trailing zeros,
/// then `suffix`.
pub(super) fn field_text(value: f64, suffix: &str, decimals: usize) -> String {