Merge pull request #5585 from dotCooCoo/fix/kerning-parentheses-wrap

Character: Kerning reads (10+5)*2 as nothing instead of 10+5*2
This commit is contained in:
BFlat
2026-11-04 19:17:33 +07:00
committed by GitHub
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 {