A number field reads "2,5" as 2.5, as a numeric keypad types it in many locales; a comma beside a point or a second comma is not guessed at.
This commit is contained in:
1 parent
4c7ea34a68
commit
8b97b9ed62
5 files changed
+38
-7
No files matched your search
@@ -1155,7 +1155,7 @@ fn canvas_panel(app: &mut SolveApp, ctx: &egui::Context) {
|
||||
let r3 = ui.add(crate::prefs::length_drag(&mut w, &app.session.doc.units, app.preferences.length_decimals).range(0.01..=1e6));
|
||||
ui.end_row();
|
||||
ui.label(crate::i18n::tr_label("Angle"));
|
||||
let r4 = ui.add(egui::DragValue::new(&mut ang).speed(1.0).suffix(" deg"));
|
||||
let r4 = ui.add(egui::DragValue::new(&mut ang).speed(1.0).suffix(" deg").custom_parser(crate::prefs::parse_number));
|
||||
ui.end_row();
|
||||
ui.label(crate::i18n::tr_label("Opacity"));
|
||||
let r5 = ui.add(egui::Slider::new(&mut op, 0.0..=1.0));
|
||||
@@ -1721,7 +1721,7 @@ fn occurrence_panel(app: &mut SolveApp, ui: &mut egui::Ui) {
|
||||
for (k, axis) in ["X angle", "Y angle", "Z angle"].iter().enumerate() {
|
||||
ui.label(*axis);
|
||||
if let Some(v) = m.angles.get_mut(k) {
|
||||
let response = ui.add(egui::DragValue::new(v).speed(1.0).suffix(" deg"));
|
||||
let response = ui.add(egui::DragValue::new(v).speed(1.0).suffix(" deg").custom_parser(crate::prefs::parse_number));
|
||||
crate::scenario::publish_handle(&format!("occurrence-move:angle:{k}"), response.rect.center());
|
||||
}
|
||||
ui.end_row();
|
||||
|
||||
@@ -2374,8 +2374,14 @@ pub fn show(app: &mut SolveApp, ctx: &egui::Context) {
|
||||
for (k, (t, r)) in mids.iter_mut().enumerate() {
|
||||
row_label(ui, "Mid Radius");
|
||||
ui.horizontal(|ui| {
|
||||
ui.add(egui::DragValue::new(t).speed(0.01).range(0.01..=0.99).fixed_decimals(2))
|
||||
.on_hover_text(tr("Position along the edge, 0 at the start end, 1 at the other"));
|
||||
ui.add(
|
||||
egui::DragValue::new(t)
|
||||
.speed(0.01)
|
||||
.range(0.01..=0.99)
|
||||
.fixed_decimals(2)
|
||||
.custom_parser(crate::prefs::parse_number),
|
||||
)
|
||||
.on_hover_text(tr("Position along the edge, 0 at the start end, 1 at the other"));
|
||||
enter |= field(ui, r);
|
||||
if ui.small_button("×").on_hover_text(tr("Remove this point")).clicked() {
|
||||
remove = Some(k);
|
||||
|
||||
@@ -390,7 +390,7 @@ pub fn rows(app: &mut SolveApp, ui: &mut egui::Ui, k: &mut Ap, inputs: &mut [Sel
|
||||
("appearance.dielectric_ior", "appearance:ior", &mut ior, 1.0..=3.0),
|
||||
] {
|
||||
row_label(ui, app.tr(label));
|
||||
let response = ui.add(egui::DragValue::new(value).range(range).speed(0.01));
|
||||
let response = ui.add(egui::DragValue::new(value).range(range).speed(0.01).custom_parser(crate::prefs::parse_number));
|
||||
crate::scenario::publish_handle(handle, response.rect.center());
|
||||
if response.changed() {
|
||||
k.remove_override = false;
|
||||
|
||||
@@ -408,7 +408,7 @@ pub fn label(k: &ConstraintKind, expr: Option<&str>, driven: bool, units: &str,
|
||||
let plain = expr.is_none_or(|e| {
|
||||
let e = e.trim();
|
||||
let e = ["mm", "cm", "in", "ft", "m", "deg", "rad", "°"].iter().find_map(|unit| e.strip_suffix(unit)).unwrap_or(e);
|
||||
e.trim().parse::<f64>().is_ok()
|
||||
crate::prefs::parse_number(e).is_some()
|
||||
});
|
||||
let text = if plain { num } else { format!("fx: {num}") };
|
||||
if driven { format!("({text})") } else { text }
|
||||
@@ -823,6 +823,8 @@ mod tests {
|
||||
let k = ConstraintKind::Length { l: 0, value: 25.0 };
|
||||
assert_eq!(label(&k, Some("25 mm"), false, "mm", 2), "25.00");
|
||||
assert_eq!(label(&k, Some("width * 2"), false, "mm", 2), "fx: 25.00");
|
||||
// A value typed with a decimal comma is a plain value too (#1347).
|
||||
assert_eq!(label(&ConstraintKind::Length { l: 0, value: 25.5 }, Some("25,5 mm"), false, "mm", 2), "25.50");
|
||||
assert_eq!(label(&k, None, true, "mm", 2), "(25.00)");
|
||||
assert_eq!(label(&ConstraintKind::Radius { c: 0, value: 5.0 }, Some("5 mm"), false, "mm", 2), "R5.00");
|
||||
assert_eq!(label(&ConstraintKind::Diameter { c: 0, value: 10.0 }, Some("10"), false, "mm", 2), "Ø10.00");
|
||||
|
||||
@@ -683,6 +683,16 @@ pub fn length_number(mm: f64, units: &str, decimals: u8) -> String {
|
||||
format!("{:.*}", length_precision(value, units, decimals), value)
|
||||
}
|
||||
|
||||
/// A plain number typed into a field, with a decimal point or a decimal comma (#1347): "2.5"
|
||||
/// and "2,5" are both 2.5, as a numeric keypad types either depending on the locale. Spaces are
|
||||
/// ignored and "−" is a minus, as in egui's own parser. A comma beside a point ("1.234,5") or a
|
||||
/// second comma is not guessed at: the text is not a number.
|
||||
pub fn parse_number(text: &str) -> Option<f64> {
|
||||
let t: String = text.chars().filter(|c| !c.is_whitespace()).map(|c| if c == '\u{2212}' { '-' } else { c }).collect();
|
||||
let t = if !t.contains('.') && t.matches(',').count() == 1 { t.replacen(',', ".", 1) } else { t };
|
||||
t.parse::<f64>().ok().filter(|v| v.is_finite())
|
||||
}
|
||||
|
||||
/// Edit a millimetre value through a control expressed in the current design units.
|
||||
/// Keep the stored value untouched unless the user actually changes the field.
|
||||
pub fn length_drag<'a>(value: &'a mut f64, units: &str, decimals: u8) -> egui::DragValue<'a> {
|
||||
@@ -1001,7 +1011,7 @@ fn page(app: &mut SolveApp, ui: &mut egui::Ui, t: &Tokens) {
|
||||
});
|
||||
ui.end_row();
|
||||
ui.label(app.tr("ui.autosave_every"));
|
||||
if ui.add(egui::DragValue::new(&mut app.autosave_minutes).range(0.0..=120.0).speed(0.5).suffix(" min")).changed() {
|
||||
if ui.add(egui::DragValue::new(&mut app.autosave_minutes).range(0.0..=120.0).speed(0.5).suffix(" min").custom_parser(parse_number)).changed() {
|
||||
set_autosave(app);
|
||||
}
|
||||
ui.end_row();
|
||||
@@ -1438,6 +1448,19 @@ pub fn set(app: &mut SolveApp, p: &serde_json::Value) -> Result<serde_json::Valu
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
#[test]
|
||||
fn number_fields_take_a_decimal_point_or_a_decimal_comma() {
|
||||
// #1347
|
||||
assert_eq!(super::parse_number("2.5"), Some(2.5));
|
||||
assert_eq!(super::parse_number("2,5"), Some(2.5));
|
||||
assert_eq!(super::parse_number(" -0,25 "), Some(-0.25));
|
||||
assert_eq!(super::parse_number("\u{2212}1,5"), Some(-1.5));
|
||||
assert_eq!(super::parse_number("12"), Some(12.0));
|
||||
for bad in ["1.234,5", "1,2,3", ",", "abc", "", "inf", "NaN"] {
|
||||
assert_eq!(super::parse_number(bad), None, "{bad}");
|
||||
}
|
||||
}
|
||||
|
||||
/// Display quality (#1287) is a preference like any other: set by name, checked, saved with
|
||||
/// the others, back to Normal with Restore Defaults.
|
||||
#[test]
|
||||
|
||||
Reference in new issue
Block a user